<commit_before><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <script type="text/javascript">
        window.onload = init;

        function DatabaseManager() {
            var version = ""; // database version, leave empty for best compatibility
            var size = 65536; // 65kB size
            this.db = window.openDatabase("AnchorModeler", version, "Storage for the Anchor Modeler", size);
        }
        DatabaseManager.prototype = {
            db: null,
            init: function() {
                this.deleteDatabase();
                this.createDatabase();
                this.execute("INSERT INTO Metadata (_timestamp, _user) values(?, ?)", [ new Date(), 'dummy' ], this.showResult, this.showError);
                this.insertAnchor("AN", "Anchor", 1, 1);
                alert("Inserting a value");
                this.insertAttribute("AN", "Anchor", "FIX", "Fixed", 1, false, 42, 1);
                alert("If the attribute value has not changed we should not get an insert");
                this.insertAttribute("AN", "Anchor", "FIX", "Fixed", 1, false, 43, 1);
                alert("Now we change the value, and this should result in an insert");
                this.insertAttribute("AN", "Anchor", "FIX", "Fixed", 1, true, 43, 1);
                alert("We should not be able to insert a duplicate primary key");
                this.insertAttribute("AN", "Anchor", "FIX", "Fixed", 1, false, 43, 1);
                // point-in-time select
                this.execute("SELECT AN.AN_ID, AN_FIX.AN_FIX_Anchor_Fixed, AN_FIX.AN_FIX_ValidFrom FROM AN_Anchor AN LEFT JOIN AN_FIX_Anchor_Fixed AN_FIX ON AN_FIX.AN_ID = AN.AN_ID AND AN_FIX.AN_FIX_ValidFrom = (SELECT MAX(sub.AN_FIX_ValidFrom) FROM AN_FIX_Anchor_Fixed sub WHERE sub.AN_ID = AN.AN_ID AND sub.AN_FIX_ValidFrom <= ?)", [42], this.showResult, this.showError);
                this.execute("SELECT AN.AN_ID, AN_FIX.AN_FIX_Anchor_Fixed, AN_FIX.AN_FIX_ValidFrom FROM AN_Anchor AN LEFT JOIN AN_FIX_Anchor_Fixed AN_FIX ON AN_FIX.AN_ID = AN.AN_ID AND AN_FIX.AN_FIX_ValidFrom = (SELECT MAX(sub.AN_FIX_ValidFrom) FROM AN_FIX_Anchor_Fixed sub WHERE sub.AN_ID = AN.AN_ID AND sub.AN_FIX_ValidFrom <= ?)", [64], this.showResult, this.showError);
                // this explain shows that sqlite does not do table elimination
                // this.execute("EXPLAIN SELECT AN_FIX_Anchor_Fixed FROM lAN_Anchor", [], this.showResult, this.showError);
                // used this one for debugging
//                this.execute("SELECT * FROM sqlite_master", [], this.showResult, this.showError);
//                this.execute("SELECT * FROM AN_FIX_Anchor_Fixed", [], this.showResult, this.showError);
            },
            createAnchor: function(anchorMnemonic, anchorDescriptor) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var anchorIdentity = anchorMnemonic + "_ID";
                var statement = "CREATE TABLE IF NOT EXISTS " + anchorName + " (" +
                        anchorIdentity + " INTEGER NOT NULL, _metadata INTEGER NOT NULL, PRIMARY KEY (" +
                        anchorIdentity + " ASC))";
                this.execute(statement, [], this.showResult, this.showError);
            },
            insertAnchor: function(anchorMnemonic, anchorDescriptor, identityValue, metadataValue) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var anchorIdentity = anchorMnemonic + "_ID";
                var statement = "INSERT INTO " + anchorName + " (" + anchorIdentity + ", _metadata) VALUES (?1, ?2)";
                this.execute(statement, [identityValue, metadataValue], this.showResult, this.showError);
            },
            deleteAnchor: function(anchorMnemonic, anchorDescriptor) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var statement = "DROP TABLE IF EXISTS " + anchorName;
                this.execute(statement, [], this.showResult, this.showError);
            },
            createAttribute: function(anchorMnemonic, anchorDescriptor, attributeMnemonic, attributeDescriptor, dataRange) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var anchorIdentity = anchorMnemonic + "_ID";
                var attributeName = anchorMnemonic + "_" + attributeMnemonic + "_" + anchorDescriptor + "_" + attributeDescriptor;
                var historizationName = anchorMnemonic + "_" + attributeMnemonic + "_ValidFrom";
                var statement = "CREATE TABLE IF NOT EXISTS " + attributeName + " (" +
                        anchorIdentity + " INTEGER NOT NULL REFERENCES " + anchorName + "(" + anchorIdentity + "), " +
                        attributeName + " " + dataRange + " NOT NULL, _metadata INTEGER NOT NULL, " +
                        historizationName + " TIMESTAMP NOT NULL, PRIMARY KEY (" + anchorIdentity + " ASC, " + historizationName + " DESC))";
                this.execute(statement, [], this.showResult, this.showError);
            },
            insertAttribute: function(anchorMnemonic, anchorDescriptor, attributeMnemonic, attributeDescriptor, identityValue, attributeValue, historizationValue, metadataValue) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var anchorIdentity = anchorMnemonic + "_ID";
                var attributeName = anchorMnemonic + "_" + attributeMnemonic + "_" + anchorDescriptor + "_" + attributeDescriptor;
                var historizationName = anchorMnemonic + "_" + attributeMnemonic + "_ValidFrom";
                var statement = "INSERT INTO " + attributeName + " (" + anchorIdentity + ", " + attributeName + ", " + historizationName + ", _metadata)" +
                        " SELECT ?1, ?2, ?3, ?4 WHERE NOT EXISTS (SELECT " + anchorIdentity + " FROM l" + anchorName + " WHERE " + anchorIdentity + " = ?1" +
                        " AND " + historizationName + " = ?2)";
                this.execute(statement, [identityValue, attributeValue, historizationValue, metadataValue], this.showResult, this.showError);
            },
            deleteAttribute: function(anchorMnemonic, anchorDescriptor, attributeMnemonic, attributeDescriptor) {
                var attributeName = anchorMnemonic + "_" + attributeMnemonic + "_" + anchorDescriptor + "_" + attributeDescriptor;
                var statement = "DROP TABLE IF EXISTS " + attributeName;
                this.execute(statement, [], this.showResult, this.showError);
            },
            createLatestView: function(anchorMnemonic, anchorDescriptor, attributeMnemonics, attributeDescriptors) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var anchorIdentity = anchorMnemonic + "_ID";
                var statement = "CREATE VIEW IF NOT EXISTS l" + anchorName + " AS SELECT " + anchorMnemonic + "." + anchorIdentity;
                var i, attributeNames = [], attributeAliases = [], historizationNames = [];
                for(i = 0; i < attributeMnemonics.length; i++) {
                    attributeNames[i] = anchorMnemonic + "_" + attributeMnemonics[i] + "_" + anchorDescriptor + "_" + attributeDescriptors[i];
                    attributeAliases[i] = anchorMnemonic + "_" + attributeMnemonics[i];
                    historizationNames[i] = attributeAliases[i] + "_ValidFrom";
                    statement += ", " + attributeAliases[i] + "." + attributeNames[i];
                    statement += ", " + attributeAliases[i] + "." + historizationNames[i];
                }
                statement += " FROM " + anchorName + " " + anchorMnemonic;
                for(i = 0; i < attributeMnemonics.length; i++) {
                    statement += " LEFT JOIN " + attributeNames[i] + " " + attributeAliases[i] +
                            " ON " + attributeAliases[i] + "." + anchorIdentity + " = " + anchorMnemonic + "." + anchorIdentity +
                            " AND " + attributeAliases[i] + "." + historizationNames[i] + " = (" +
                            " SELECT MAX(sub." + historizationNames[i] + ") FROM " + attributeNames[i] + " sub" +
                            " WHERE sub." + anchorIdentity + " = " + anchorMnemonic + "." + anchorIdentity + ")";
                }
                this.execute(statement, [], this.showResult, this.showError);
            },
            deleteLatestView: function(anchorMnemonic, anchorDescriptor) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var statement = "DROP VIEW IF EXISTS l" + anchorName;
                this.execute(statement, [], this.showResult, this.showError);
            },
            createMetadata: function() {
                var statement = "CREATE TABLE IF NOT EXISTS Metadata (_metadata INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, _timestamp TIMESTAMP, _user TEXT)";
                this.execute(statement, [], this.showResult, this.showError);
            },
            deleteMetadata: function() {
                var statement = "DROP TABLE IF EXISTS Metadata";
                this.execute(statement, [], this.showResult, this.showError);
            },
            createDatabase: function() {
                this.createMetadata();
                this.createAnchor("KN", "Knot");
                this.createAttribute("KN", "Knot", "FIX", "Fixed", "BOOLEAN");
                this.createAttribute("KN", "Knot", "XPO", "XPosition", "DECIMAL(10,2)");
                this.createAttribute("KN", "Knot", "YPO", "YPosition", "DECIMAL(10,2)");
                this.createAttribute("KN", "Knot", "IDY", "Identity", "INTEGER");
                this.createAttribute("KN", "Knot", "MNE", "Mnemonic", "TEXT");
                this.createAttribute("KN", "Knot", "DSC", "Descriptor", "TEXT");
                this.createAttribute("KN", "Knot", "DRA", "DataRange", "TEXT");
                this.createLatestView("KN", "Knot", ["FIX", "XPO", "YPO", "IDY", "MNE", "DSC", "DRA"], ["Fixed", "XPosition", "YPosition", "Identity", "Mnemonic", "Descriptor", "DataRange"]);
                this.createAnchor("AN", "Anchor");
                this.createAttribute("AN", "Anchor", "FIX", "Fixed", "BOOLEAN");
                this.createAttribute("AN", "Anchor", "XPO", "XPosition", "DECIMAL(10,2)");
                this.createAttribute("AN", "Anchor", "YPO", "YPosition", "DECIMAL(10,2)");
                this.createAttribute("AN", "Anchor", "IDY", "Identity", "INTEGER");
                this.createAttribute("AN", "Anchor", "MNE", "Mnemonic", "TEXT");
                this.createAttribute("AN", "Anchor", "DSC", "Descriptor", "TEXT");
                this.createLatestView("AN", "Anchor", ["FIX", "XPO", "YPO", "IDY", "MNE", "DSC"], ["Fixed", "XPosition", "YPosition", "Identity", "Mnemonic", "Descriptor"]);
            },
            deleteDatabase: function() {
                // reverse order of creation
                this.deleteLatestView("AN", "Anchor");
                this.deleteAttribute("AN", "Anchor", "IDY", "Identity");
                this.deleteAttribute("AN", "Anchor", "MNE", "Mnemonic");
                this.deleteAttribute("AN", "Anchor", "DSC", "Descriptor");
                this.deleteAttribute("AN", "Anchor", "FIX", "Fixed");
                this.deleteAttribute("AN", "Anchor", "XPO", "XPosition");
                this.deleteAttribute("AN", "Anchor", "YPO", "YPosition");
                this.deleteAnchor("AN", "Anchor");
                this.deleteLatestView("KN", "Knot");
                this.deleteAttribute("KN", "Knot", "FIX", "Fixed");
                this.deleteAttribute("KN", "Knot", "XPO", "XPosition");
                this.deleteAttribute("KN", "Knot", "YPO", "YPosition");
                this.deleteAttribute("KN", "Knot", "IDY", "Identity");
                this.deleteAttribute("KN", "Knot", "MNE", "Mnemonic");
                this.deleteAttribute("KN", "Knot", "DSC", "Descriptor");
                this.deleteAttribute("KN", "Knot", "DRA", "DataRange");
                this.deleteAnchor("KN", "Knot");
                this.deleteMetadata();
            },
            execute: function(sql, params, resultFunction, errorFunction)  {
                this.db.transaction(function(tx) {
                    tx.executeSql(
                        sql,
                        params,
                        function(tx, result) {
                            if(resultFunction)
                                resultFunction(result);
                        },
                        function(tx, error) {
                            if(errorFunction)
                                errorFunction(error);
                        }
                    );
                });
            },
            showResult: function(result) {
                var row, member;
                for(var i = 0; i < result.rows.length; i++) {
                    var message = "";
                    row = result.rows.item(i);
                    for(member in row) {
                        message += member + ": " + row[member] + "\n";
                    }<commit_msg>Continuing work on the DB manager.<commit_after><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <script type="text/javascript">
        window.onload = init;

        function DatabaseManager() {
            var version = ""; // database version, leave empty for best compatibility
            var size = 65536; // 65kB size
            this.db = window.openDatabase("AnchorModeler", version, "Storage for the Anchor Modeler", size);
        }
        DatabaseManager.prototype = {
            db: null,
            init: function() {
                this.deleteDatabase();
                this.createDatabase();
                var now = Number(new Date());
                this.insertAnchor("AN", "Anchor", 1);
                // alert("Inserting a value");
                this.insertAttribute("AN", "Anchor", "FIX", "Fixed", 1, false, now);
                // alert("If the attribute value has not changed we should not get an insert");
                this.insertAttribute("AN", "Anchor", "FIX", "Fixed", 1, false, (now + 1));
                // alert("Now we change the value, and this should result in an insert");
                this.insertAttribute("AN", "Anchor", "FIX", "Fixed", 1, true, (now + 1));
                // alert("We should not be able to insert a duplicate primary key");
                this.insertAttribute("AN", "Anchor", "FIX", "Fixed", 1, false, (now + 1));
                // alert("Point-in-time select - in the past");
                this.selectAttribute("AN", "Anchor", "FIX", "Fixed", now);
                // alert("Point-in-time select - in the future");
                this.selectAttribute("AN", "Anchor", "FIX", "Fixed", (now + 64));
                // this explain shows that sqlite does not do table elimination
                // this.execute("EXPLAIN SELECT AN_FIX_Anchor_Fixed FROM lAN_Anchor", [], this.showResult, this.showError);
                // used this one for debugging
//                this.execute("SELECT * FROM sqlite_master", [], this.showResult, this.showError);
//                this.execute("SELECT * FROM AN_FIX_Anchor_Fixed", [], this.showResult, this.showError);
            },
            createAnchor: function(anchorMnemonic, anchorDescriptor) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var anchorIdentity = anchorMnemonic + "_ID";
                var statement = "CREATE TABLE IF NOT EXISTS " + anchorName + " (" +
                        anchorIdentity + " INTEGER NOT NULL, PRIMARY KEY (" +
                        anchorIdentity + " ASC))";
                this.execute(statement, [], this.showResult, this.showError);
            },
            insertAnchor: function(anchorMnemonic, anchorDescriptor, identityValue) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var anchorIdentity = anchorMnemonic + "_ID";
                var statement = "INSERT INTO " + anchorName + " (" + anchorIdentity + ") VALUES (?1)";
                this.execute(statement, [identityValue], this.showResult, this.showError);
            },
            deleteAnchor: function(anchorMnemonic, anchorDescriptor) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var statement = "DROP TABLE IF EXISTS " + anchorName;
                this.execute(statement, [], this.showResult, this.showError);
            },
            createAttribute: function(anchorMnemonic, anchorDescriptor, attributeMnemonic, attributeDescriptor, dataRange) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var anchorIdentity = anchorMnemonic + "_ID";
                var attributeName = anchorMnemonic + "_" + attributeMnemonic + "_" + anchorDescriptor + "_" + attributeDescriptor;
                var historizationName = anchorMnemonic + "_" + attributeMnemonic + "_ValidFrom";
                var statement = "CREATE TABLE IF NOT EXISTS " + attributeName + " (" +
                        anchorIdentity + " INTEGER NOT NULL REFERENCES " + anchorName + "(" + anchorIdentity + "), " +
                        attributeName + " " + dataRange + " NOT NULL, " +
                        historizationName + " TIMESTAMP NOT NULL, PRIMARY KEY (" + anchorIdentity + " ASC, " + historizationName + " DESC))";
                this.execute(statement, [], this.showResult, this.showError);
            },
            insertAttribute: function(anchorMnemonic, anchorDescriptor, attributeMnemonic, attributeDescriptor, identityValue, attributeValue, historizationValue) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var anchorIdentity = anchorMnemonic + "_ID";
                var attributeName = anchorMnemonic + "_" + attributeMnemonic + "_" + anchorDescriptor + "_" + attributeDescriptor;
                var historizationName = anchorMnemonic + "_" + attributeMnemonic + "_ValidFrom";
                var statement = "INSERT INTO " + attributeName + " (" + anchorIdentity + ", " + attributeName + ", " + historizationName + ")" +
                        " SELECT ?1, ?2, ?3 WHERE NOT EXISTS (SELECT " + anchorIdentity + " FROM l" + anchorName + " WHERE " + anchorIdentity + " = ?1" +
                        " AND " + historizationName + " = ?2)";
                this.execute(statement, [identityValue, attributeValue, historizationValue], this.showResult, this.showError);
            },
            selectAttribute: function(anchorMnemonic, anchorDescriptor, attributeMnemonic, attributeDescriptor, timepoint) {
                var anchorIdentity = anchorMnemonic + "_ID";
                var attributeAlias = anchorMnemonic + "_" + attributeMnemonic;
                var attributeName =  attributeAlias + "_" + anchorDescriptor + "_" + attributeDescriptor;
                var historizationName = anchorMnemonic + "_" + attributeMnemonic + "_ValidFrom";
                var statement = "SELECT * FROM " + attributeName + " " + attributeAlias + " WHERE " + historizationName +
                        " = (SELECT MAX(sub." + historizationName + ") FROM " + attributeName + " sub WHERE sub." + anchorIdentity +
                        " = " + attributeAlias + "." + anchorIdentity + " AND sub." + historizationName + " <= ?)";
                this.execute(statement, [timepoint], this.showResult, this.showError);
            },
            deleteAttribute: function(anchorMnemonic, anchorDescriptor, attributeMnemonic, attributeDescriptor) {
                var attributeName = anchorMnemonic + "_" + attributeMnemonic + "_" + anchorDescriptor + "_" + attributeDescriptor;
                var statement = "DROP TABLE IF EXISTS " + attributeName;
                this.execute(statement, [], this.showResult, this.showError);
            },
            createLatestView: function(anchorMnemonic, anchorDescriptor, attributeMnemonics, attributeDescriptors) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var anchorIdentity = anchorMnemonic + "_ID";
                var statement = "CREATE VIEW IF NOT EXISTS l" + anchorName + " AS SELECT " + anchorMnemonic + "." + anchorIdentity;
                var i, attributeNames = [], attributeAliases = [], historizationNames = [];
                for(i = 0; i < attributeMnemonics.length; i++) {
                    attributeNames[i] = anchorMnemonic + "_" + attributeMnemonics[i] + "_" + anchorDescriptor + "_" + attributeDescriptors[i];
                    attributeAliases[i] = anchorMnemonic + "_" + attributeMnemonics[i];
                    historizationNames[i] = attributeAliases[i] + "_ValidFrom";
                    statement += ", " + attributeAliases[i] + "." + attributeNames[i];
                    statement += ", " + attributeAliases[i] + "." + historizationNames[i];
                }
                statement += " FROM " + anchorName + " " + anchorMnemonic;
                for(i = 0; i < attributeMnemonics.length; i++) {
                    statement += " LEFT JOIN " + attributeNames[i] + " " + attributeAliases[i] +
                            " ON " + attributeAliases[i] + "." + anchorIdentity + " = " + anchorMnemonic + "." + anchorIdentity +
                            " AND " + attributeAliases[i] + "." + historizationNames[i] + " = (" +
                            " SELECT MAX(sub." + historizationNames[i] + ") FROM " + attributeNames[i] + " sub" +
                            " WHERE sub." + anchorIdentity + " = " + anchorMnemonic + "." + anchorIdentity + ")";
                }
                this.execute(statement, [], this.showResult, this.showError);
            },
            deleteLatestView: function(anchorMnemonic, anchorDescriptor) {
                var anchorName = anchorMnemonic + "_" + anchorDescriptor;
                var statement = "DROP VIEW IF EXISTS l" + anchorName;
                this.execute(statement, [], this.showResult, this.showError);
            },
            createDatabase: function() {
                this.createAnchor("MO", "Model");
                this.createAttribute("MO", "Model", "REA", "Reason", "TEXT");
                this.createAttribute("MO", "Model", "VFR", "ValidFrom", "TIMESTAMP");
                this.createLatestView("MO", "Model", ["REA", "VFR"], ["Reason", "ValidFrom"]);
                this.createAnchor("KN", "Knot");
                this.createAttribute("KN", "Knot", "FIX", "Fixed", "BOOLEAN");
                this.createAttribute("KN", "Knot", "XPO", "XPosition", "DECIMAL(10,2)");
                this.createAttribute("KN", "Knot", "YPO", "YPosition", "DECIMAL(10,2)");
                this.createAttribute("KN", "Knot", "IDY", "Identity", "INTEGER");
                this.createAttribute("KN", "Knot", "MNE", "Mnemonic", "TEXT");
                this.createAttribute("KN", "Knot", "DSC", "Descriptor", "TEXT");
                this.createAttribute("KN", "Knot", "DRA", "DataRange", "TEXT");
                this.createLatestView("KN", "Knot", ["FIX", "XPO", "YPO", "IDY", "MNE", "DSC", "DRA"], ["Fixed", "XPosition", "YPosition", "Identity", "Mnemonic", "Descriptor", "DataRange"]);
                this.createAnchor("AN", "Anchor");
                this.createAttribute("AN", "Anchor", "FIX", "Fixed", "BOOLEAN");
                this.createAttribute("AN", "Anchor", "XPO", "XPosition", "DECIMAL(10,2)");
                this.createAttribute("AN", "Anchor", "YPO", "YPosition", "DECIMAL(10,2)");
                this.createAttribute("AN", "Anchor", "IDY", "Identity", "INTEGER");
                this.createAttribute("AN", "Anchor", "MNE", "Mnemonic", "TEXT");
                this.createAttribute("AN", "Anchor", "DSC", "Descriptor", "TEXT");
                this.createLatestView("AN", "Anchor", ["FIX", "XPO", "YPO", "IDY", "MNE", "DSC"], ["Fixed", "XPosition", "YPosition", "Identity", "Mnemonic", "Descriptor"]);
            },
            deleteDatabase: function() {
                // reverse order of creation
                this.deleteLatestView("AN", "Anchor");
                this.deleteAttribute("AN", "Anchor", "IDY", "Identity");
                this.deleteAttribute("AN", "Anchor", "MNE", "Mnemonic");
                this.deleteAttribute("AN", "Anchor", "DSC", "Descriptor");
                this.deleteAttribute("AN", "Anchor", "FIX", "Fixed");
                this.deleteAttribute("AN", "Anchor", "XPO", "XPosition");
                this.deleteAttribute("AN", "Anchor", "YPO", "YPosition");
                this.deleteAnchor("AN", "Anchor");
                this.deleteLatestView("KN", "Knot");
                this.deleteAttribute("KN", "Knot", "FIX", "Fixed");
                this.deleteAttribute("KN", "Knot", "XPO", "XPosition");
                this.deleteAttribute("KN", "Knot", "YPO", "YPosition");
                this.deleteAttribute("KN", "Knot", "IDY", "Identity");
                this.deleteAttribute("KN", "Knot", "MNE", "Mnemonic");
                this.deleteAttribute("KN", "Knot", "DSC", "Descriptor");
                this.deleteAttribute("KN", "Knot", "DRA", "DataRange");
                this.deleteAnchor("KN", "Knot");
            },
            execute: function(sql, params, resultFunction, errorFunction)  {
                this.db.transaction(function(tx) {
                    tx.executeSql(
                        sql,
                        params,
                        function(tx, result) {
                            if(resultFunction)
                                resultFunction(result);
                        },
                        function(tx, error) {
                            if(errorFunction)
                                errorFunction(error);
                        }
                    );
                });
            },
            showResult: function(result) {
                var row, member;
                for(var i = 0; i < result.rows.length; i++) {
                    var message = "";
                    row = result.rows.item(i);
                    for(member in row) {
                        message += member + ": " + row[member] + "\n";
                    }
{'fraction_non_alphanumeric': 0.1380734118716618, 'fraction_numerical': 0.0038637827190423878, 'mean_word_length': 2.045333948552313, 'pattern_counts': {'":': 2, '<': 20, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7344370', 'n_tokens_mistral': 7260, 'n_tokens_neox': 6699, 'n_words': 1569}