/**
* Super Contsructor to call in inheriting classes
* @class
*
* @classdesc Base class for all inheriting analyzers. Provides common functionality
* and parsing of all question files. Children use the information and searchers populated
* here to provide application specific feedback.
*
* This class is not intended to be directly instantiated. It's children are.
*
* @example
* function subAnalyzer(){
* analyzerBase.call(this);
*
* subAnalyzer specific members
* and methods
*
* }
* subAnalyzer.prototype = new analyzerBase();
* subAnalyzer.prototype.constructor = subAnalyzer;
*
* @see {@link OrgnomAnalyzer}
* @see {@link spectroAnalyzer}
*
* @tutorial NomenclatureQuestionFileFormat
* @tutorial SpectroscopyQuestionFileFormat
* @tutorial ArchitectureOverview
*
*/
function analyzerBase() {
// public members -----------------------------
/** The category of the question. Example: ethers for orgnom, or empty for spectroscopy.
* defaults to the 'category' cookie value
* @type {String} */
this.category = $.cookie("category");
/** The question number, from the category, being analyzed.
* defaults to the 'question' cookie value
* @type {String} */
this.questionNum = $.cookie("question");
/** Functional Class of the Analyzer. Example: orgnom or spectroscopy,<br>
* used, in part, to determine the location of the question files.
* defaults to the 'fclass' cookie value
* @type {String} */
this.fclass = $.cookie("fClass");
// private members-----------------------------
/** Used in private members called from the constructor
* @type {analyzerBase} */
var that = this;
/** @type {Boolean} */
var questionCompleted = false;
/**The running total average score for the category
* @type {Number} */
var score = 0.0;
/** A constructed string using the config and fclass
* @type {String} */
var answerURL = config.getBaseUrl() + this.fclass + config.STN
+ this.category + config.QDIR_PREFIX + this.questionNum + "/"
+ config.ANSWER_FILE_NAME;
/**The value from the question file for a help page link.
* Can be a relative or absolute URL.
* @type {String} */
var helpURL = "";
// private members to store the answer information in
/** Used to analyze responses against the values from the question file for correct answers.
* @type {searcher} */
var correctSearcher = null;
/** The jme or SMILE String for the question. jme for orgnom, SMILE for spectroscopy
* @type {String} */
var jme = "jme not set";
/** A constructed relative URL to the difficulty img for the question.
* @type {String} */
var difSrc = "../img/e.gif"; // as a default
/** Used to analyze responses against the value from the question file for common wrong answers.
* @type {searcher} */
var commonSearchers = new Array(); // Searcher for common sections
/**Used to analyze responses against the values from the question file for strings to search for in the answer.
* @type {Array.<searcher>} */
var searchers = new Array(); // Serachers for search sections
//========Ornom itesm. candidates to move to OrgnomAnalyzer
/** The type found in the question file for the question.
* used in orgnom
* @type {String} */
var typeMessage = config.DEFAULT_NOM_TYPE_MSG;
/** Used to analyze responses against the value from the question file for the
* number of loci. Used in orgnom
* @type {searcher} */
var lSearcher = null; // Searder for Loci sections
/** Used to analyze responses against the value from the question file for common wrong answers.
* @type {searcher} */
/**
* @type {Number}
*/
var numberOfHints = 0; //we'll parse it, but use it as a changeable index to cycle hints
/**
* @type {Array.<String>}
*/
var hints = new Array();
//============== spectro section ============
/**
* Contains searchers based on the spectroscopy question file
* format. Is populated by the parse methods of this class.
*
* @tutorial SpectroscopyQuestionFileFormat
* @example
* {
* "mw" : molecularWeightSearcher
* "stereo" : searcher,
* "typesC" : numTypesCarbonSearcher,
* "typesH" : numTypesHydrogenSearcher,
* "numC" : numCarbonSearcher,
* "numH" : numHydrogenSearcher,
* "charge" : chargeSearcher,
* "rings" : ringsSearcher,
* "molF" : molecularFormulaSearcher,
* "fGroups" : functionalGroupsSearcher
* }
*
* @type {Object}
*/
var spectroSearchers = {"mw": molecularWeightSearcher,
"stereo": searcher,
"typesC" : numTypesCarbonSearcher,
"typesH": numTypesHydrogenSearcher,
"numC" : numCarbonSearcher ,
"numH" : numHydrogenSearcher,
"charge" : chargeSearcher,
"rings" : ringsSearcher,
"molF" : molecularFormulaSearcher,
"fGroups": functionalGroupsSearcher};
//some of spectro sections are optional so we need defaults
spectroSearchers.stereo = new searcher("/ZZZZZXY987/", "", "");
spectroSearchers.fGroups = new functionalGroupsSearcher(null, "", "");
// register the AJAX error callback via jquery
$(document).ajaxError(function(event, jqxhr, settings, exception) {
that.loadError(event, jqxhr, settings, exception);
});
// =========================Private methods =====================
/**
* The callback handler for the AJAX call to obtain the question file. It
* splits the file into sections, delimited by '@', then passes the section
* to a section specific parser.
* <p>It does all question file parsing.
*
* @method
* @access private
* @tutorial QuestionFileFormatNomenclature
* @tutorial QuestionFileFormatSpectroscopy
* @param data value returned from AJAX
* @param status value returned from AJAX
* @throws a parse error if any of the section parsers throw an exception
*
*/
function parseQuestionFile(data, status) {
// Split the sections into an Array
var Arr = data.split("@");
try {
for (var int = 0; int < Arr.length; int++) {
section = Arr[int];
// determine the type of section and
// dispatch accordingly
//used in orgnom and spectro
if (/^correct/i.test(section)) {
parseCorrect(section);
continue;
}
//used in orgnom and spectro
if (/^difficulty/i.test(section)) {
parseDifficulty(section);
continue;
}
//used in orgnom
if (/^jme/i.test(section)) {
parseJme(section);
continue;
}
//used in orgnom
if (/^loci/i.test(section)) {
parseLoci(section);
continue;
}
//used in orgnom
if (/^type\stype/i.test(section)) {
parseType(section);
continue;
}
//used in orgnom and maybe spectro
if (/^search/i.test(section)) {
parseSearch(section);
continue;
}
//used in orgnom and spectro
if(/^link/i.test(section)){
parseLink(section);
continue;
}
//used in orgnom and spectro
if (/\scommon/i.test(section)) {
parseCommon(section);
continue;
}
//used in spectro
if(/^hint\shint/i.test(section)){
parseHintNum(section);
continue;
}
//used in spectro
if(/^hint\d\d*\s*hint/i.test(section)){
parseHint(section);
continue;
}
//used in spectro
if(/^mw\s*\d/i.test(section)){
parseMolecularWeight(section);
continue;
}
//used in spectro
if(/^stereo\s/i.test(section)){
parseStereo(section);
continue;
}
//used in spectro
if(/^c\s*\d/i.test(section)){
parseNumberCarbons(section);
continue;
}
//used in spectro
if(/^h\s*\d/i.test(section)){
parseNumberHydrogens(section);
continue;
}
//used in spectro
if(/^typec\s*\d/i.test(section)){
parseNumberTypesCarbons(section);
continue;
}
//used in spectro
if(/^typeh\s*\d/i.test(section)){
parseNumberTypesHydrogens(section);
continue;
}
//used in spectro
if(/^charge\s*\d/i.test(section)){
parseCharge(section);
continue;
}
//used in spectro
if(/^rings\s*\d/i.test(section)){
parseRings(section);
continue;
}
//used in spectro
if(/^mf\s/i.test(section)){
parseMolecularFormula(section);
continue;
}
//used in spectro
if(/^fg\s/i.test(section)){
parseFunctionalGroups(section);
continue;
}
// anything else in the file is ignored
}
} catch (e) {
throw config.AF_LOAD_ERROR + " \n\nParse Error in " + e;
}
}
/**
* Parses the functional Group section from the question file and stores the
* result in spectroSearchers.fGroups
*
* @param section the link section from the question file.
* @private
* @method
*
*/
function parseFunctionalGroups(section){
var lines = getSectionLines(section, /^fg\s*/i);
spectroSearchers.fGroups = new functionalGroupsSearcher(lines[0].trim(), lines[1], lines[2].substr(1));
}
/**
* Parses the mf section from the question file and stores the
* result in spectroSearchers.molF
*
* @param section the link section from the question file.
* @private
* @method
*
*/
function parseMolecularFormula(section){
var lines = getSectionLines(section, /^mf\s*/i);
spectroSearchers.molF = new molecularFormulaSearcher(lines[0].trim(), lines[1], lines[2].substr(1));
}
/**
* Parses the charge section from the question file and stores the
* result in spectroSearchers.charge
*
* @param section the link section from the question file.
* @private
* @method
*
*/
function parseCharge(section){
var lines = getSectionLines(section, /^charge\s*/i);
spectroSearchers.charge = new chargeSearcher(lines[0], lines[1].substr(1));
}
/**
* Parses the ring section from the question file and stores the
* result in spectroSearchers.rings
*
* @param section the link section from the question file.
* @private
* @method
*
*/
function parseRings(section){
var lines = getSectionLines(section, /^rings\s*/i);
spectroSearchers.rings = new ringsSearcher(lines[0], lines[1].substr(1));
}
/**
* Parses the typeh section from the question file and stores the
* result in spectroSearchers.typeH
*
* @param section the link section from the question file.
* @private
* @method
*
*/
function parseNumberTypesHydrogens(section){
var lines = getSectionLines(section, /^typeh\s*/i);
spectroSearchers.typesH = new numTypesHydrogenSearcher(lines[0], lines[1], lines[2].substr(1));
}
/**
* Parses the typec section from the question file and stores the
* result in spectroSearchers.typeC
*
* @param section the link section from the question file.
* @private
* @method
*
*/
function parseNumberTypesCarbons(section){
var lines = getSectionLines(section, /^typec\s*/i);
spectroSearchers.typesC = new numTypesCarbonSearcher(lines[0], lines[1], lines[2].substr(1));
}
/**
* Parses the h section from the question file and stores the
* result in spectroSearchers.numH
*
* @param section the link section from the question file.
* @private
* @method
*
*/
function parseNumberHydrogens(section){
var lines = getSectionLines(section, /^h\s*/i);
spectroSearchers.numH = new numHydrogenSearcher(lines[0], lines[1], lines[2].substr(1));
}
/**
* Parses the c section from the question file and stores the
* result in spectroSearchers.numC
*
* @param section the link section from the question file.
* @private
* @method
*
*/
function parseNumberCarbons(section){
var lines = getSectionLines(section, /^c\s*/i);
spectroSearchers.numC = new numCarbonSearcher(lines[0], lines[1], lines[2].substr(1));
}
/**
* Parses the stereo section from the question file and stores the
* result in spectroSearchers.stereo
*
* @param section the link section from the question file.
* @private
* @method
*
*/
function parseStereo(section){
var lines = getSectionLines(section, /^stereo\s/i);
spectroSearchers.stereo = new searcher(lines[0].trim(), lines[1], "");
//alert(typeof spectroSearchers.stereo);
}
/**
* Parses the mw section from the question file and stores the
* result in spectroSearchers.mw
*
* @param section the link section from the question file.
* @private
* @method
*
*/
function parseMolecularWeight(section){
var lines = getSectionLines(section, /^mw\s*/i);
spectroSearchers.mw = new molecularWeightSearcher(lines[0], lines[1], lines[2].substr(1));
}
/**
* Parses the hint section from the question file and stores
* the result in numberOfHints.
*
* @param section the link section from the question file.
* @private
* @method
*
*/
function parseHintNum(section){
var lines = getSectionLines(section, /^hint\s*hint\s*/i);
numberOfHints = lines[0];
//we reset it so we can use it to
//feed the hints
numberOfHints = 0;
}
/**
* Parses the hintN section(s) from the question file and adds the
* result to the hints array
*
* @param section the link section from the question file.
* @private
* @method
*
*/
function parseHint(section){
var lines = getSectionLines(section, /^hint\d\d*\s*hint\s*/i);
hints.push(lines[0]);
}
/**
* Parses the help link section from the question file and stores the
* result in this.helpURL
* @param section the link section from the question file.
* @private
* @method
* @throws 'parsLink' on error
*
*/
function parseLink(section){
try{
var lines = getSectionLines(section, /^link\s*help\s*/i);
helpURL = lines[0];
}catch(e){
throw " parseLink ";
}
}
/**
* Parses the correct section from the question file and creates a
* searcher from the result
* @param section correct section of question file.
* @private
* @method
* @throws 'parseCorrect' on error
*/
function parseCorrect(section) {
try {
var lines = getSectionLines(section, /^correct\s*/i);
correctSearcher = new searcher(lines[0].trim(), lines[1], null);
} catch (e) {
throw " parseCorrect ";
}
}
/**
* Sets the img src string based on the difficulty of the question.
*
* @param section the difficulty section from the question file.
* @private
* @method
* @throws 'parseDifficulty' on error
*/
function parseDifficulty(section) {
try {
var lines = getSectionLines(section, /^difficulty\s*difficulty\s*/i);
difSrc = "../img/e.gif"; //default just in case
if (lines[0][0] == "e") {
difSrc = "../img/e2.gif";
}
if (lines[0][0] == "m") {
difSrc = "../img/m2.gif";
}
if (lines[0][0] == "d") {
difSrc = "../img/d2.gif";
}
if (lines[0][0] == "x") {
difSrc = "../img/x2.gif";
}
} catch (e) {
throw " parseDifficulty ";
}
}
/**
* Sets the type message string of the question.
* @param section the type section from the question file.
* @private
* @method
* @throws 'parseType' on error
*/
function parseType(section) {
try {
var lines = getSectionLines(section, /^type\s*type\s*/i);
typeMessage += "of this " + lines[0];
} catch (e) {
throw " parseType ";
}
}
/**
* Sets the SMILE string of the question.
* @param section the JME section from the question file.
* @private
* @method
* @throws 'parseJME' on error
*/
function parseJme(section) {
try {
var lines = getSectionLines(section, /^jme\s*jme\s*/i);
jme = lines[0];
} catch (e) {
throw " parseJME ";
}
}
/**
* Parses the loci section from the question file and creates a
* {@link lociSearcher} from the result.
* @param section the loci section from the question file.
* @private
* @method
* @throws 'parseLoci' on error
*/
function parseLoci(section) {
try {
var lines = getSectionLines(section, /^loci\s*/i);
lSearcher = new lociSearcher(lines[0], lines[1].substr(1,
lines[1].length - 1));
} catch (e) {
throw " parseLoci ";
}
}
/**
* Parses a search section from the question file, creates a
* {@link searcher} for it and adds it to the searchers array.
* @param section a search section from the question file.
* @private
* @method
* @throws 'parseSection' on error
*/
function parseSearch(section) {
try {
var lines = getSectionLines(section, /^search\s*/i);
var regEx = lines[0].substr(0, lines[0].length - 1); // the last char is a \r so we remove it
var positiveMsg = "";
var negativeMsg = "";
if ('$' != lines[1][0]) {
positiveMsg = lines[1];
} else {
negativeMsg = lines[1].substr(1); // remove the $ from the string
}
if (lines[2]) { // if there is a second line
if ('$' != lines[2][0]) {
positiveMsg = lines[2]; // overwrites the first if there were 2.
} else {
negativeMsg = lines[2].substr(1);
}
}
// add this searcher to the analyzers array of searchers
searchers.push(new searcher(regEx, positiveMsg, negativeMsg));
} catch (e) {
throw " parseSearch ";
}
}
/**
*
* Parses the common section from the question file and creates a
* {@link searcher} from the result. <p>
* The common section is different in that the string common does not appear
* at the beginning of the section like the other section names do.
* Common appears last on the first line of the section. This is the only way we can tell it
* is a common section, but the question files seem consistent in doing this.
* @param section the common section from the question file.
* @private
* @method
* @throws 'parseCommon' on error
*/
function parseCommon(section) {
try {
var lines = section.split(/\s*common\s*/i);
var regEx = lines[0];
var positiveMsg = "";
var negativeMsg = "";
lines = lines[1].split(/\n/);
// section is only concerned with
// either 1 or 2 lines.
// anything else is ignored
if ('$' != lines[0][0]) {
positiveMsg = lines[0];
} else {
negativeMsg = lines[0].substr(1);
}
if (lines[1]) { // if there is a second line
if ('$' != lines[1][0]) {
positiveMsg = lines[1]; // overwrites the first if there were 2.
} else {
negativeMsg = lines[1].substr(1);
}
}
//alert(regEx);
var commonSearcher = new searcher(regEx, positiveMsg, negativeMsg);
commonSearchers.push(commonSearcher);
} catch (e) {
throw " parseCommon ";
}
}
/**
* Helper method that splits the section into lines, except for parseCommon.
* Relies on each line being separate. (splits on newlines).
* @private
* @method
* @param {String} section the section from the question file to split into lines.
* @param regExp the reqular expression used to split the first line from the remaining lines
* @returns {Array.<String>} each element is a line, delimited by \n in the section.
*/
function getSectionLines(section, regExp) {
return section.split(regExp)[1].split(/\n/);
}
// =========================privileged methods =====================
/**
* Global AJAX callback for failed AJAX requests. Most likely cause of the
* failure would be file not found.
* @throws {String} config.AF_LOAD_ERROR;
* @access protected
* @method
* @throws 'File Not Fund Error'
*/
this.loadError = function(anevent, ajqxhr, thesettings, anexception) {
throw config.AF_LOAD_ERROR + "\n\nFile Not Found Error ";
};
/**
* AJAX (made globally Synchronous) to get the question file. we have to do
* synchronous because the jsmeonLoand function needs this.jme to be set and
* available before it(jsmeOnloand) is called.
*
* This method should be called from the children of analyzerBase in their
* constructors. After construction, children should only use the
* loadQuestionFile(qClass, category,qnum) method.
*
* @see {@link analyzerBase}
* @access protected
* @method
*/
this.getQuestionFile = function() {
$.ajaxSetup({
async : false
});
// alert("Loading: " + this.getAnswerURL());
$.get(this.getAnswerURL(), function(data, status) {
parseQuestionFile(data, status);
});
};
/**
* Reloads the analyzer with a new questiod, based on functional class,
* category and qnum. Resets the the cookies for each parameter if the parameter
* is not NUll.
*
* If this method is called with all Null parameters it will reload the current
* question file.
*
* @param {string} qClass
* @param {string} category
* @param {string} qnum
* @access protected
* @method
*
*/
this.loadQuestionFile = function(qClass, category, qnum) {
// alert( category + " "+ qnum);
try {
// sets the member value and cookie
if (qClass != null) {
this.setfclass(qClass);
$.cookie("fclass", qClass, {
path : '/'
});
}
if (category != null) {
this.setCategory(category);
$.cookie("category", category, {
path : '/'
});
}
if (qnum != null) {
this.setQuestionNum(qnum);
$.cookie("question", qnum, {
path : '/'
});
}
this.setURL(config.getBaseUrl() + this.fclass + config.STN
+ this.category + config.QDIR_PREFIX + this.questionNum
+ "/" + config.ANSWER_FILE_NAME);
this.reset();
this.getQuestionFile();
} catch (e) {
// rethrow the error
throw e;
}
};
/**
* Called by loadQuestion file. Resets the class in preperation to make
* a call to getQuestionFile so that parseQuestionFile will populate the
* searchers and other information properly from the new question file information.
* @access protected
* @method
*/
this.reset = function() {
searchers = new Array();
correctSearcher = null;
commonSearchers = new Array();
spectroSearchers.stereo = new searcher("/zzzz987wrtywd/", "", ""); //needs default for spectro
lSearcher = null;
typeMessage = config.DEFAULT_NOM_TYPE_MSG;
questionCompleted = false;
jme = null;
helpURL = "";
numberOfHints = 0;
hints = new Array();
spectroSearchers.fGroups = new functionalGroupsSearcher(null, "", "");
};
/**
* Getter for the Help URL from the question file.
* @returns {String} the help URL
*/
this.getHelpURL = function(){
return helpURL;
};
/**
* Sets the URL for the question file location. Use with
* caution
*
* @param {String} value
* @access protected
* @method
*
*/
this.setURL = function(value) {
answerURL = value;
};
/**
* Sets the Functional Class
* @param {String} value
* @access protected
* @method
*/
this.setfclass = function(value) {
this.fclass = value;
};
/**
* Sets the Category
* @param {String} value
* @access protected
* @method
*/
this.setCategory = function(value) {
this.category = value;
};
/**
* Sets the question number (for the cateory)
* @param {String} value
* @access protected
* @method
*/
this.setQuestionNum = function(value) {
this.questionNum = value;
};
/**
* @returns the maximum attempts for this question. Used
* to determine when to show the solution and allow another
* question to be selected.
* @access protected
* @method
*/
this.getMaxAttempts = function() {
return config.MAXATTEMPTS;
};
/**
* Set the question score. Used by inheriting classes.
* @param {Number} value
* @access protected
*/
this.setScore = function(value) {
score = value;
};
/**
* @returns {String} the URL to the question File
* @access protected
*/
this.getAnswerURL = function() {
return answerURL;
};
/**
* @returns {Number} the Question Score if the question was completed zero otherwise.
* @access protected
*/
this.getScore = function() {
return score;
};
/**
* @returns {Boolean}
* @access protected
*/
this.isCompleted = function() {
return questionCompleted;
};
/**
* Set the complete flag for the question.
* @access protected
*/
this.setComplete = function() {
questionCompleted = true;
};
/**
* Clear the complete flag for the question.
* @access protected
*/
this.clearComplete = function() {
questionCompleted = false;
};
/**
* @returns {String} the Message from the question file for a correct answer.
* @access protected
*/
this.getCorrectMsg = function() {
return correctSearcher.getfoundMsg();
};
/**
* @returns {String} for the reqular expression
* @access protected
*/
this.getCorrectAnswer = function() {
return correctSearcher.getRegExpString();
};
/**
* checks that answer is an exact case insensitive match with any one of the
* acceptable answers found in the question file.
*
* @param {String} answer a string trimmed of leading and trailing
* whitespace prior to calling this method.
*
* @returns {Boolean} true if it is an exact match.
* @access protected
*
*/
this.isCorrect = function(answer) {
if (correctSearcher.test(answer)) {
// the answer is found by the regex (ie. the regex is at least
// a subset of the answer)
// now test for an exact match with one of the regex values
answerUpper = answer.toUpperCase();
var correctAnswers = correctSearcher.getRegExpString().split("|");
for (var int = 0; int < correctAnswers.length; int++) {
var toTest = correctAnswers[int].toUpperCase();
if (answerUpper == toTest) {
return true;
}
}
}
// if we get here then the given answer
// had something else in it.
return false;
};
/**
* @returns {String} representing the relative path to the image to use
* for the difficulty img on the question page. The path is built
* based on the difficulty value in the question file.
* @access protected
*/
this.getDifficulty = function() {
return difSrc;
};
/**
* @returns {String} the type message from the question file.
* @access protected
*/
this.getType = function() {
return typeMessage;
};
/**
* @returns the JME string found in the question file.
* access protected
*/
this.getJme = function() {
return jme;
};
/**
* @returns {lociSearcher} the loci searcher for the question
* @access protected
*/
this.getLociSearcher = function() {
return lSearcher;
};
/**
* This method should be implemented by children of this class to provide
* meaningful feedback.
*
* It is provided as a default to facilitate design for new presentations
* using analyzers.
* @param {string} answer
* @throws String
* @virtual
* @access protected
*/
this.getFeedback = function(answer) {
throw "analyzerBase.getFeedBack must be overriden by inheriting classes"
+ " in order to provide meaningful feedback";
};
this.getHint = function(){
if(numberOfHints >= hints.length){
numberOfHints = 0;
}
return hints[numberOfHints++];
};
/**
* This method should be implemented by children of this class to provide
* meaningful syntax validation
*
* It is provided as a default to facilitate design for new presentations
* using analyzers.
* @param {string} answer
* @throws String
* @virtual
* @access protected
*/
this.checkSyntax = function(answer) {
throw "analyzerBase.checkSyntax must be overriden by inheriting classes"
+ " in order to provide syntax validation";
};
/**
* @returns {searcher} The first common searcher in the array of common searchers or
* null if no common searchers are present.
* @access protected
*/
this.getCommonSearcher = function() {
if(commonSearchers.length > 0){
return commonSearchers[0];
}
return null;
};
/**
* @returns [{searcher}] The array of common searchers or
* null if no common searchers are present.
* @access protected
*/
this.getCommonSearchers = function() {
if(commonSearchers.length > 0){
return commonSearchers;
}
return null;
};
/**
* @returns {Array.<searcher>} the array of Searchers other than common, correct and loci.
* @access protected
*/
this.getSearchers = function() {
return searchers;
};
this.getMolecularFormulaSearcher = function(){
return spectroSearchers.molF;
};
this.getMolecularWeightSearcher = function(){
return spectroSearchers.mw;
};
this.getStereoSearcher = function(){
return spectroSearchers.stereo;
};
this.getFunctionalGroupsSearcher = function(){
return spectroSearchers.fGroups;
};
this.getTypesCarbonSearcher = function(){
return spectroSearchers.typesC;
};
this.getTypesHydrogenSearcher = function(){
return spectroSearchers.typesH;
};
this.getNumCargonSearcher = function(){
return spectroSearchers.numC;
};
this.getNumHydrogenSearcher = function(){
return spectroSearchers.numH;
};
this.getChargeSearcher = function(){
return spectroSearchers.charge;
};
this.getRingsSearcher = function(){
return spectroSearchers.rings;
};
}