FlightGear wiki:Instant-Refs: Difference between revisions

Jump to navigation Jump to search
m
→‎The script: extend firefox xpi/addon stub, prototype a GA/GP based regex/xpath solver using the genetic.js framework (just loaded, not used by default currently)
m (→‎The script: extend firefox xpi/addon stub, prototype a GA/GP based regex/xpath solver using the genetic.js framework (just loaded, not used by default currently))
Line 446: Line 446:
// @require    https://code.jquery.com/jquery-1.10.2.js
// @require    https://code.jquery.com/jquery-1.10.2.js
// @require    https://code.jquery.com/ui/1.11.4/jquery-ui.js
// @require    https://code.jquery.com/ui/1.11.4/jquery-ui.js
// @require    http://subprotocol.com/js/genetic-0.1.12.min.js
// @resource    jQUI_CSS https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css
// @resource    jQUI_CSS https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css
// @resource    myLogo http://wiki.flightgear.org/images/2/25/Quotes-logo-200x200.png
// @resource    myLogo http://wiki.flightgear.org/images/2/25/Quotes-logo-200x200.png
Line 480: Line 481:


'use strict';
'use strict';


// TODO: move to GreaseMonkey/UI host
// TODO: move to GreaseMonkey/UI host
Line 519: Line 521:
var Environment = {
var Environment = {
   getHost: function(xpi=false) {
   getHost: function(xpi=false) {
   
     if(xpi) {
     if(xpi) {
       Environment.scriptEngine = 'firefox addon';
       Environment.scriptEngine = 'firefox addon';
Line 603: Line 605:
     } // foreach test
     } // foreach test
   }, // runAPITests
   }, // runAPITests
 
  /*
  * ===================================================================================================================================================
  *
  */
    
    
   // NOTE: This mode/environment is WIP and highly experimental ...
   // NOTE: This mode/environment is WIP and highly experimental ...
Line 645: Line 652:
   }
   }
});
});
 
    // for selection handling stuff, see: https://developer.mozilla.org/en-US/Add-ons/SDK/High-Level_APIs/selection
   
    function myListener() {
  console.log("A selection has been made.");
}
var selection = require("sdk/selection");
selection.on('select', myListener);
   
}, //registerTrigger
}, //registerTrigger
      
      
get_persistent: function(key, default_value) {return default_value;},
get_persistent: function(key, default_value) {
    // https://developer.mozilla.org/en-US/Add-ons/SDK/High-Level_APIs/simple-storage
    var ss = require("sdk/simple-storage");
   
    console.log("firefox mode does not yet have persistence support");
    return default_value;},
set_persistent: function(key, value) {
set_persistent: function(key, value) {
console.log("persistence stubs not yet filled in !");
console.log("persistence stubs not yet filled in !");
},
},
 
   
set_clipboard: function() {
 
// https://developer.mozilla.org/en-US/Add-ons/SDK/High-Level_APIs/selection
set_clipboard: function(content) {
console.log('clipboard stub not yet filled in ...');
// https://developer.mozilla.org/en-US/Add-ons/SDK/High-Level_APIs/clipboard
}
   
//console.log('clipboard stub not yet filled in ...');
    var clipboard = require("sdk/clipboard");
    clipboard.set(content);
} //set_cliipboard
   }, // end of FireFox addon config
   }, // end of FireFox addon config
 
  // placeholder for now ...
  Android: {
    // NOP
  }, // Android


    
    
Line 890: Line 920:
     [].forEach.call(CONFIG['FlightGear.wiki'].modes, function(mode) {
     [].forEach.call(CONFIG['FlightGear.wiki'].modes, function(mode) {
       //dbLog("Checking trigger:"+mode.name);
       //dbLog("Checking trigger:"+mode.name);
       if(mode.trigger) {
       if(mode.trigger() ) {
         mode.handler();
         mode.handler();
       }
       }
Line 1,199: Line 1,229:
         value: article.name, // FIXME: just a placeholder for now
         value: article.name, // FIXME: just a placeholder for now
         text : article.name  
         text : article.name  
     }));
     })); //append option
   });
   }); // foreach
     }
     } // updateArticleList
      
      
     // add the article list to the corresponding dropdown menus
     // add the article list to the corresponding dropdown menus
Line 1,210: Line 1,240:
       var article = this.value;
       var article = this.value;
        
        
     
    // HACK: try to get a login token (actually not needed just for reading ...)
     Host.download('http://wiki.flightgear.org/api.php?action=query&prop=info|revisions&intoken=edit&rvprop=timestamp&titles=Main%20Page', function (response) {
     Host.download('http://wiki.flightgear.org/api.php?action=query&prop=info|revisions&intoken=edit&rvprop=timestamp&titles=Main%20Page', function (response) {
     var message = 'FlightGear wiki login status (AJAX):';
     var message = 'FlightGear wiki login status (AJAX):';
     var status = response.statusText;
     var status = response.statusText;
      
      
    // populate dropdown menu with article sections
     if (status === 'OK') {
     if (status === 'OK') {
      
      
Line 1,222: Line 1,253:
         try {
         try {
       var sections = JSON.parse(response.responseText);
       var sections = JSON.parse(response.responseText);
        }
           
        catch (e) {
      $('div#options select#section_select', markup).empty(); // delete all sections
          alert(e.message);
        }
       
        //alert("Finsihed downloading FAQ sections:\n"+sections.parse.sections[0].line );
   
      $('div#options select#section_select', markup).empty(); // delete all sections
        
        
       $.each(sections.parse.sections, function (i, section) {
       $.each(sections.parse.sections, function (i, section) {
Line 1,237: Line 1,262:
     }));
     }));
   }); //foreach section
   }); //foreach section
        }
        catch (e) {
          alert(e.message);
        }
          
          
       }); //downoad sections
        //alert("Finsihed downloading FAQ sections:\n"+sections.parse.sections[0].line );
   
           
       }); //download sections
      
      
          
          
Line 1,249: Line 1,282:
     }); // on select change
     }); // on select change
      
      
  // init the tab stuff
   markup.tabs();
   markup.tabs();
    
    
Line 1,274: Line 1,308:
   };
   };
      
      
  // actually show our tabbed dialog using the params above
   markup.dialog(diagParam);
   markup.dialog(diagParam);
      
      
Line 1,279: Line 1,314:
   } // jQueryTabbed()  
   } // jQueryTabbed()  
    
    
};
}; // output methods


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Line 1,998: Line 2,033:
   return str.replace(/_/g, ' ');
   return str.replace(/_/g, ' ');
}
}
</syntaxhighlight>
 
// IGNORE THIS:
// This is an experiment to use GA/GP (genetic programming) to help procedurally evolve xpath and regex expressions if/when the underlying websites change
// so that we don't have to manually update/edit the script accordingly (this would also work for mobile themes etc)
// For now, this is heavily based on the genetic.js framework/examples: http://subprotocol.com/system/genetic-hello-world.html
// The idea is to evolve the xpath/regex expression by evaluating its return value against the expected/desired value
// the most important thing here is having a suitable fitness function
//
 
 
try {
 
var genetic = Genetic.create();
 
// TODO: use minimizer: redundant_bytes + duration_msec + xpath.length
genetic.optimize = Genetic.Optimize.Maximize;
genetic.select1 = Genetic.Select1.Tournament2;
genetic.select2 = Genetic.Select2.Tournament2;
 
genetic.seed = function() {
 
    function randomString(len) {
        var text = "";
        var charset = "\\abcdefghijklmnopqrstuvwxyz0123456789 ()<>*.,";
        for(var i=0;i<len;i++)
            text += charset.charAt(Math.floor(Math.random() * charset.length));
       
        return text;
    }
   
    // create random strings that are equal in length to solution
    return randomString( this.userData["solution"].length);
};
 
 
genetic.mutate = function(entity) {
   
    function replaceAt(str, index, character) {
        return str.substr(0, index) + character + str.substr(index+character.length);
    }
   
    // chromosomal drift
    var i = Math.floor(Math.random()*entity.length);
    return replaceAt(entity, i, String.fromCharCode(entity.charCodeAt(i) + (Math.floor(Math.random()*2) ? 1 : -1)));
};
 
genetic.crossover = function(mother, father) {
 
    // two-point crossover
    var len = mother.length;
    var ca = Math.floor(Math.random()*len);
    var cb = Math.floor(Math.random()*len);   
    if (ca > cb) {
        var tmp = cb;
        cb = ca;
        ca = tmp;
    }
       
    var son = father.substr(0,ca) + mother.substr(ca, cb-ca) + father.substr(cb);
    var daughter = mother.substr(0,ca) + father.substr(ca, cb-ca) + mother.substr(cb);
   
    return [son, daughter];
};
   
genetic.determineExcessBytes = function (text, needle) {
    return text.length - needle.length;
};
   
genetic.containsText = function (text, needle) {
    return text.search(needle);
};
 
genetic.isValid = function(exp) {
 
};
   
/* myFitness:
* - must be a valid xpath/regex expression (try/call)
* - must containsText the needle
* - low relative offset in text (begin/end)
* - excessBytes
* - short expression  (expression length)
* - expression footprint (runtime)
*/
 
// TODO: the fitness function should validate each xpath/regex first
   
   
genetic.fitness = function(entity) {
    var fitness = 0;
    var result;
    var validExp = 0.1;
    var hasToken = 0.1;
   
    var searchSpace = this.userData.searchSpace;
    var expect = this.userData.expect;
   
   
    // promote regex expressions that don't throw an exception
 
    if (0)
    try {
    var regex = new RegExp(entity);
    searchSpace.match(regex);
    validExp=10;
    }
        catch(e) {
    }
   
    //if (searchSpace.match(regex).match(expect)) hasToken = 20;
       
       
    var i;
    for (i=0;i<entity.length;++i) {
        // increase fitness for each character that matches
        if (entity[i] == this.userData["solution"][i])
            fitness += 1;
       
        // award fractions of a point as we get warmer
        fitness += (127-Math.abs(entity.charCodeAt(i) - this.userData["solution"].charCodeAt(i)))/50;
    }
 
    return fitness + (1*validExp + 1* hasToken);
};
 
genetic.generation = function(pop, generation, stats) {
    // stop running once we've reached the solution
    return pop[0].entity != this.userData["solution"];
};
 
genetic.notification = function(pop, generation, stats, isFinished) {
 
    function lerp(a, b, p) {
        return a + (b-a)*p;
    }
   
    var value = pop[0].entity;
    this.last = this.last||value;
   
    if (pop != 0 && value == this.last)
        return;
 
   
    var solution = [];
    var i;
    for (i=0;i<value.length;++i) {
   
    solution.push(value[i]);
}
    console.log("Generation:"+ generation + " Fitness:" + pop[0].fitness.toPrecision(5) + " Solution:" + solution.join(""));
 
    this.last = value;
};
   
   
$('document').ready(function() { 
 
var config = {
            "iterations": 4000
            , "size": 250
            , "crossover": 0.3
            , "mutation": 0.4
            , "skip": 20
            //, "webWorkers": false
        };
 
 
/*
var profile = CONFIG['Sourceforge Mailing list'];
var posting = profile.tests[0];
var author_xpath = profile.title.xpath;
*/
 
// the regex we want to evolve
var solution = "/From: (.*) <.*@.*>/";
var searchSpace = "From: John Doe <John@do...> - 2020-07-02 17:36:03";
var expect = "John Doe";
 
// let's assume, we'd like to evolve a regex expression like this one
var userData = {
            solution: solution,
            searchSpace: searchSpace,
            expect: expect
                       
};   
   
if(0) // disabled by default
    genetic.evolve(config, userData);
}); // document.ready()
   
 
 
console.log("genetic.js is loaded and working, but disabled for now");   
   
 
} // try
catch (e) {
  console.log("genetic.js error:\n" +e.message);
} // catch</syntaxhighlight>


{{Appendix}}
{{Appendix}}

Navigation menu