function formObj(s_objname_fp,f_formready_fp,s_langpath_fp,s_cusspath_fp,s_timepath_fp,s_countrylistpath_fp,s_statelistpath_fp) {
    //dependencies: ajax_class.js
    //constants
    var DEF_CALENDAR = [{"month":1,"length":31},{"month":2,"length":28},{"month":3,"length":31},{"month":4,"length":30},{"month":5,"length":31},{"month":6,"length":30},{"month":7,"length":31},{"month":8,"length":31},{"month":9,"length":30},{"month":10,"length":31},{"month":11,"length":30},{"month":12,"length":31}];
    var DEF_POSTALCODES = {"1":"[0-9][0-9][0-9][0-9]","2":"[a-z][0-9][a-z]\\s*[0-9][a-z][0-9]","3":"[a-z][a-z][0-9][0-9]\\s*[0-9][a-z][a-z]","4":"[0-9][0-9][0-9][0-9][0-9]","5":"[0-9][0-9][0-9][0-9]","6":"[0-9][0-9][0-9][0-9][0-9]","7":"[0-9][0-9][0-9][0-9]","8":"[0-9][0-9][0-9][0-9][0-9]","9":"[0-9][0-9][0-9][0-9][0-9]","10":"[0-9][0-9][0-9][0-9][0-9]","11":"[0-9][0-9][0-9][0-9]","12":"[0-9][0-9][0-9][0-9][0-9]"}; //this list is in id order against db (au,ca,uk,us,be,fr,lu,es,mx,de,nl)
    var DEF_DATESEP = '-';
    var DEF_GENDER = ["f","m"];
    var DEF_IDDAYSEL = 'in-day-sel';
    var DEF_IDCONF1TXT = 'in-a-txt';
    var DEF_IDCONF2TXT = 'in-b-txt';
    var DEF_IDCOUNTRYSEL = 'in-country-sel';
    var DEF_IDGENDRSEL = 'in-gender-sel';
    var DEF_IDMONTHSEL = 'in-month-sel';
    var DEF_IDSTATESEL = 'in-state-sel';
    var DEF_IDYEARSEL = 'in-year-sel';
    var DEF_NONSELECT = "!";
    var HTML_CBOXINPUT = '<div id="_id1_"><input type="checkbox" _checked_ id="_id2_" /> _label_</div>';
    var HTML_CBOXSUFFIX = '-ck';
    var HTML_CHECKED = 'checked';
    var HTML_CONDEVAL2ELE = "if(document.getElementById('_id1_').value === document.getElementById('_id2_').value){_trueact_}else{_falseact_}";
    var HTML_CONDEVALSELF = "if(this.value === _value_){_trueact_}else{_falseact_}";
    var HTML_DIVELEPREFIX = 'div-';
    var HTML_INPUTPREFIX = 'in-';
    var HTML_MTHCLRELE = ".doClearElement('_id_');";
    var HTML_MTHOUTDAYSEL = '.outDaySelect();';
    var HTML_MTHOUTINLERR = ".outInlineMsg('_id_','_value_');";
    var HTML_MTHOUTMNTHSEL = '.outMonthSelect();';
    var HTML_MTHOUTSTATESEL = '.outStateSelect();';
    var HTML_MTHOUTSUBLNK = '.outSubmitLink();';
    var HTML_RADIOINPUT = '<input type="radio" id="_id_" onclick="_onclick_" value="_value_" name="_name_" />';
    var HTML_SELECT = '<select id="_id_" onchange="_onchange_">_option_</select>';
    var HTML_SELECTOPTION = '<option value="_value_">_option_</option>';
    var HTML_SUBMITLINK = '<span><a href="#" onclick="_onclick_">_submit_</a></span>';
    var HTML_TEXTINPUT = '<input type="_type_" onkeyup="_onkeyup_" id="_id_" size="_size_" maxlength="_maxlen_" value="_value_" />';
    var KEY_AGE = 'age';
    var KEY_COMPLETE = 1;
    var KEY_COUNTRYID = 'country_id';
    var KEY_DOB = 'dob';
    var KEY_ERREMAILMATCH = 'err-emailmatch';
    var KEY_LBLCOUNTRY = 'label-country';
    var KEY_LBLDAY = 'label-day';
    var KEY_LBLGENDER = 'label-gender';
    var KEY_LBLMONTH = 'label-month';
    var KEY_LBLPASSWORD = 'label-password'; 
    var KEY_LBLSTATE = 'label-state';
    var KEY_LBLSUBMIT = 'label-submit';
    var KEY_LBLUSERNAME = 'label-username';
    var KEY_LBLYEAR = 'label-year';
    var KEY_LENGTH = 'length';
    var KEY_LOCALNAME = 'local_name';
    var KEY_LOGIN = 'login';
    var KEY_LISTGENDER = 'list-gender';
    var KEY_LISTMONTH = 'list-months';
    var KEY_MONTH = 'month';
    var KEY_PASSWORD = 'password';
    var KEY_REG = 'registration';
    var KEY_REQUEST = 0;
    var KEY_TEXT = 'text';
    var RGX_CHECKED = /_checked_/g;
    var RGX_FLSEACT = /_falseact_/g;
    var RGX_ID = /_id_/g;
    var RGX_ID1 = /_id1_/g;
    var RGX_ID2 = /_id2_/g;
    var RGX_LABEL = /_label_/g;
    var RGX_LGLEMAIL = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i;
    var RGX_ILGLACCENT = /[\300-\377]+/;
    var RGX_ILGLEMAILPUNCT = /[!~`#$%^&*()=+\[\]{}|\\:;"'<>,?/]+/;
    var RGX_ILGLFORMAT = /[\t\r\n\v\f]+/;
    var RGX_ILGLPUNCT = /[!~`@#$%^&*()=+\[\]{}|\\:;"'<>,.?/]+/;
    var RGX_MAXLEN = /_maxlen_/g;
    var RGX_NAME = /_name_/g;
    var RGX_ONCLICK = /_onclick_/g;
    var RGX_ONCHANGE = /_onchange_/g;
    var RGX_ONKEYUP = /_onkeyup_/g;
    var RGX_ONSELECT = /_onselect_/g;
    var RGX_OPTION = /_option_/g;
    var RGX_SIZE = /_size_/g;
    var RGX_SPACE = /\s/;
    var RGX_SUBMIT = /_submit_/g;
    var RGX_TRUEACT = /_trueact_/g;
    var RGX_TYPE = /_type_/g;
    var RGX_VALUE = /_value_/g;

    //private variables
    var a_countrylist; //list of available countries
    var a_cuss; //container for bad word list via external ajax call
    var a_lang; //container for lang returned via external ajax call
    var a_loadtracker; //requested load/completed load item tracker
    var a_statelist; //list of states for available countries
    var d_now; //time/datestamp as set from ajax call
    var f_formready; //method/function to call after an external event is complete
    var i_maxlen; //integer of max length, any max length
    var i_maxyear; //start year for year select
    var i_minyear; //end year for year select
    var i_size; //integer of size, any size
    var s_cboxdivid; //div id of container for checkbox(es)
    var s_daydivid; //id of DOB 'day' div
    var s_genderdivid; //id of gender div
    var s_input1divid; //id of email1 div
    var s_input2divid; //id of email2 div
    var s_langkey1; //key1 for lang array, when set externally
    var s_langkey2; //key2 for lang array, when set externally
    var s_nameroot; //root of any dynamically generated name/id
    var s_monthdivid; //id of DOB 'month' div
    var s_objname; //callback name of instance
    var s_statedivid; //id of state div
    var s_submitdivid; //id of submit link div
    var s_submitact; //onclick action for submit link
    var s_yeardivid; //id of DOB 'year' div

    //public method pointers
    this.doClearElement = doClearElement; //empty the contents of a DOM element
    this.doValidateBadwords = doValidateBadwords; //validate for all the shittin bad words you can fucking think of, asshole!
    this.doValidateCheckBoxes = doValidateCheckBoxes; //outputs array of check/notcheck values for the last cb list generated
    this.doValidateDOB = doValidateDOB; //validate DOB
    this.doValidateName = doValidateName; //validate a name for bad words and formatting
    this.doValidatePassword = doValidatePassword;
    this.doValidateEmail = doValidateEmail; //validate e-mail for formatting and bad words
    this.doValidatePostalcode = doValidatePostalcode; //validate a postal code
    this.doValidateUsername = doValidateUsername;
    this.getInputValue = getInputValue;
    this.outCheckboxInput = outCheckboxInput; //output one or more checkboxes and labels
    this.outConfirmedFieldInput = outConfirmedFieldInput; //output field + confirmation field for text input
    this.outCountrySelect = outCountrySelect; //output the country selector input
    this.outDaySelect = outDaySelect; //output day select menu of date (only works in tandem with outYearSelect and outMonthSelect)
    this.outGenderSelect = outGenderSelect; //output gender select menu
    this.outInlineMsg = outInlineMsg; //output a status/error message to a DOM element
    this.outLoginInput = outLoginInput;
    this.outMonthSelect = outMonthSelect; //output month select menu of date (only works in tandem with outDaySelect and outYearSelect)
    this.outRadioInput = outRadioInput;
    this.outSingleFieldInput = outSingleFieldInput; //output a single text field
    this.outStateSelect = outStateSelect;
    this.outSubmitLink = outSubmitLink; //output a 'submit' link
    this.outTextInput = outTextInput; //output a naked text field
    this.outYearSelect = outYearSelect; //output year select menu of date (only works in tandem with outMonthSelect and outDaySelect)
    this.setCheckbox = setCheckbox; //set params of checkbox input(s)
    this.setConfirmedFieldInput = setConfirmedFieldInput; //set params of field + confirmation field text input
    this.setDateSelect = setDateSelect; //set params of date selector input
    this.setGenderSelect = setGenderSelect; //set params of gender selector input
    this.setLoginInput = setLoginInput;
    this.setRegionSelect = setRegionSelect; //set the params for a state select input
    this.setSingleFieldInput = setSingleFieldInput; //set params for a single field input
    this.setSubmitLink = setSubmitLink; //set submit link params if submit link is written independently

    //"constructor" actions
    f_formready = f_formready_fp;
    setCallback(s_objname_fp);
    setLoadTracker();
    getBadwords(s_cusspath_fp);
    getCountryList(s_countrylistpath_fp);
    getForm(s_langpath_fp);
    getStateList(s_statelistpath_fp);
    getTime(s_timepath_fp);

    //public methods
    function doClearElement(s_eleid_fp) {
        doUpdateElement(s_eleid_fp,'');
    }

    function doValidateBadwords(s_haystack_fp) {
        var i_index;
        for (i_index = 0; i_index < a_cuss.length; i_index++) {
            if (s_haystack_fp.indexOf(a_cuss[i_index]) !== -1) {
                return false;
            }
        }
        return true;
    }

    function doValidateCheckBoxes() { //this must be called BEFORE building any other inputs for all the necessary vars to be available
        var a_result = new Array();
        var i_loop;
        for (i_loop = 0; i_loop < a_lang[s_langkey1][s_langkey2].length; i_loop++) {
            if (document.getElementById(HTML_INPUTPREFIX + s_nameroot + (i_loop + 1) + HTML_CBOXSUFFIX).checked) { //do the bool-int conversion now!
                a_result[i_loop] = 1;
            } else {
                a_result[i_loop] = 0;
            }
        }
        return a_result;
    }

    function doValidateDOB() { //returns an array of BOTH dob & age on success
        var a_dob = new Array();
        var d_dob;
        var s_dob;
        s_dob = getInputValue(DEF_IDYEARSEL) + '-' + getInputValue(DEF_IDMONTHSEL) + '-' + getInputValue(DEF_IDDAYSEL);
        d_dob = outDate(s_dob);
        if (d_dob >= d_now) {
            return false;
        } else {
            i_age = outAge(d_dob);
            a_dob[KEY_DOB] = d_dob;
            a_dob[KEY_AGE] = i_age;
            return a_dob;
        }
    }

    function doValidateEmail() {
        if (doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_LGLEMAIL) === true && doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_ILGLACCENT) !== true && doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_ILGLEMAILPUNCT) !== true && doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_ILGLFORMAT) !== true && doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_SPACE) !== true) {
            return getInputValue(DEF_IDCONF1TXT);
        } else {
            return false;
        }
    }

    function doValidateName() {
        if (doValidateBadwords(getInputValue(DEF_IDCONF1TXT)) === true && doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_ILGLPUNCT) !== true && doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_ILGLFORMAT) !== true) {
            return getInputValue(DEF_IDCONF1TXT);
        } else {
            return false;
        }
    }

    function doValidatePostalcode(s_postalcode_fp,i_countrycode_fp) {
        var rx_pattern;
        var b_return;
        rx_pattern = new RegExp(DEF_POSTALCODES[i_countrycode_fp], 'i');
        b_return = doValidatePattern(s_postalcode_fp,rx_pattern);
        return b_return;
    }

    function doValidateUsername() {
        if (doValidateBadwords(getInputValue(DEF_IDCONF1TXT)) === true && doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_ILGLACCENT) !== true && doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_ILGLPUNCT) !== true && doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_ILGLFORMAT) !== true && doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_SPACE) !== true && getInputValue(DEF_IDCONF1TXT).length > 1 && getInputValue(DEF_IDCONF1TXT).length < 51) {
            return getInputValue(DEF_IDCONF1TXT);
            //this moves to the last step
            //duplicate check happens in acctutils; php will return a false due to mysql error on violation of unique constraint on username that can then be used to send back to last step with appropriate error message
        } else {
            return false;
        }
    }

    function doValidatePassword() {
        if (doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_ILGLACCENT) !== true && doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_ILGLPUNCT) !== true && doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_ILGLFORMAT) !== true && doValidatePattern(getInputValue(DEF_IDCONF1TXT),RGX_SPACE) !== true && getInputValue(DEF_IDCONF1TXT).length > 1 && getInputValue(DEF_IDCONF1TXT).length < 51) {
            return getInputValue(DEF_IDCONF1TXT); //return the password already MD5 encoded
        } else {
            return false;
        }
    }

    function getInputValue(s_eleid_fp) {
        if (document.getElementById(s_eleid_fp).value) {
            var m_value = document.getElementById(s_eleid_fp).value;
            return m_value;
        } else {
            return false;
        }
    }

    function outCheckboxInput(a_checked_fp) {
        //outCheckboxInput differs from the other output writers!
        //* uses a container div to populate with divs of checkbox items
        //* shows the submit button only if given params for it but without any runtime conditions
        //* dynamically names input elements
        //* is not paired with a validator
        //* takes just a list of labels and dynamically generates ids/divs (e.g. in-[s_nameroot][1-...]-ck) based on label's position in list
    	var i_loop;
        var s_cbox = '';
        var s_tmpcheck;
        for (i_loop = 0; i_loop < a_lang[s_langkey1][s_langkey2].length; i_loop++) {
            if (a_checked_fp) {
                s_tmpcheck = a_checked_fp[i_loop];
            } else {
                s_tmpcheck = '';
            }
            s_cbox += outCheckbox(a_lang[s_langkey1][s_langkey2][i_loop], (i_loop+1), s_tmpcheck);
        }
        doUpdateElement(s_cboxdivid,s_cbox);
        if (s_submitdivid != '') {
            outSubmitLink();
        }
    }

    function outConfirmedFieldInput(m_value_fp) {
        var s_input1;
        var s_input2;
        var s_falseact = s_objname + HTML_MTHOUTINLERR;
        var s_onkeyup;
        var s_trueact;
        s_trueact = s_objname + HTML_MTHOUTSUBLNK;
        s_falseact = s_falseact.replace(RGX_ID,s_submitdivid);
        s_falseact = s_falseact.replace(RGX_VALUE,a_lang[s_langkey1][s_langkey2]);
        s_onkeyup = out2WayCondChng(DEF_IDCONF1TXT,DEF_IDCONF2TXT,s_trueact,s_falseact);
        s_input1 = outTextInput(DEF_IDCONF1TXT,i_size,i_maxlen,s_onkeyup,m_value_fp);
        s_input2 = outTextInput(DEF_IDCONF2TXT,i_size,i_maxlen,s_onkeyup,m_value_fp);
        doUpdateElement(s_input1divid,s_input1);
        doUpdateElement(s_input2divid,s_input2);
        doUpdateElement(s_submitdivid,a_lang[s_langkey1][s_langkey2]);
    }

    function outCountrySelect() {
        var i_index;
        var s_falseaction;
        var s_formselect;
        var s_month;
        var s_onchange;
        var s_opts;
        var s_trueaction;
        //write the initial label line selector
        s_opts = outSelectOption(DEF_NONSELECT,a_lang[KEY_REG][KEY_LBLCOUNTRY]);
        //write the actual value lines
        for (i_index in a_countrylist) {
            s_opts += outSelectOption(a_countrylist[i_index][KEY_COUNTRYID],a_countrylist[i_index][KEY_LOCALNAME]);
        }
        //set the onchange to blank out day if label option is selected, show day if not
        s_trueaction = s_objname + HTML_MTHCLRELE.replace(RGX_ID,s_submitdivid);
        s_trueaction += s_objname + HTML_MTHCLRELE.replace(RGX_ID,s_statedivid);
        s_falseaction = s_objname + HTML_MTHOUTSTATESEL;
        s_falseaction += s_objname + HTML_MTHCLRELE.replace(RGX_ID,s_submitdivid);
        s_onchange = outSelfCondChng("'" + DEF_NONSELECT + "'",s_trueaction,s_falseaction);
        //write the full input element
        s_formselect = outSelect(DEF_IDCOUNTRYSEL,s_opts,s_onchange);
        //then send the month selector
        doUpdateElement(s_countrydivid,s_formselect);
    }

    function outDaySelect() {
        var i_loop;
        var i_month = getInputValue(DEF_IDMONTHSEL);
        var i_monthlength = DEF_CALENDAR[i_month - 1][KEY_LENGTH];
        var i_year = getInputValue(DEF_IDYEARSEL);
        var s_opts;
        //deal with the leap year
        if (i_year%4 === 0 && i_month === "2") {
            i_monthlength = 29;
        }
        //write the initial label line selector
        s_opts = outSelectOption(DEF_NONSELECT,a_lang[KEY_REG][KEY_LBLDAY]);
        //write the list of days
        for (i_loop = 1; i_loop <= i_monthlength; i_loop++) {
            s_opts += outSelectOption(i_loop,i_loop);
        }
        //write the full input element
        //set the onchange to blank out submit if label option is selected, show submit if not
        s_formselect = outSelect(DEF_IDDAYSEL,s_opts,outSubmitSelOnChng());
        //update the element on the page
        doUpdateElement(s_daydivid,s_formselect);
    }

    function outInlineMsg(s_eleid_fp,s_err_fp) {
        doUpdateElement(s_eleid_fp,s_err_fp);
    }

    function outGenderSelect() {
        var i_loop;
        var s_opts;
        //write the label line selector
        s_opts = outSelectOption(DEF_NONSELECT,a_lang[KEY_REG][KEY_LBLGENDER]);
        //write the list of options
        for (i_loop = 0; i_loop < 2; i_loop++) {
            s_opts += outSelectOption(DEF_GENDER[i_loop],a_lang[KEY_REG][KEY_LISTGENDER][i_loop]);
        }
        //write the full input element
        //set the onchange to blank out submit if label option is selected, show submit if not
        s_formselect = outSelect(DEF_IDGENDRSEL,s_opts,outSubmitSelOnChng());
        //update the element on the page
        doUpdateElement(s_genderdivid,s_formselect);
    }

    function outLoginInput() {
        s_fieldtype = KEY_TEXT;
        s_usernamefld = a_lang[KEY_LOGIN][KEY_LBLUSERNAME] + ' ' + outTextInput(DEF_IDCONF1TXT,i_size,i_maxlen,'','');
        doUpdateElement(s_input1divid, s_usernamefld);
        s_fieldtype = KEY_PASSWORD;
        s_passwordfld = a_lang[KEY_LOGIN][KEY_LBLPASSWORD] + ' ' + outTextInput(DEF_IDCONF2TXT,i_size,i_maxlen,'','')
        doUpdateElement(s_input2divid, s_passwordfld);
        outSubmitLink();
    }
    
    function outMonthSelect() {
        var i_index;
        var s_falseaction;
        var s_formselect;
        var s_month;
        var s_onchange;
        var s_opts;
        var s_trueaction;
        //write the initial label line selector
        s_opts = outSelectOption(DEF_NONSELECT,a_lang[KEY_REG][KEY_LBLMONTH]);
        //write the actual value lines
        for (i_index = 0; i_index < DEF_CALENDAR.length; i_index++) {
            s_month = a_lang[KEY_REG][KEY_LISTMONTH][i_index];
            s_opts += outSelectOption(DEF_CALENDAR[i_index][KEY_MONTH],s_month);
        }
        //set the onchange to blank out day if label option is selected, show day if not
        s_trueaction = s_objname + HTML_MTHCLRELE.replace(RGX_ID,s_submitdivid);
        s_trueaction += s_objname + HTML_MTHCLRELE.replace(RGX_ID,s_daydivid);
        s_falseaction = s_objname + HTML_MTHOUTDAYSEL;
        s_falseaction += s_objname + HTML_MTHCLRELE.replace(RGX_ID,s_submitdivid);
        s_onchange = outSelfCondChng("'" + DEF_NONSELECT + "'",s_trueaction,s_falseaction);
        //write the full input element
        s_formselect = outSelect(DEF_IDMONTHSEL,s_opts,s_onchange);
        //if day was up, blank it out
        doUpdateElement(s_daydivid,'');
        //then send the month selector
        doUpdateElement(s_monthdivid,s_formselect);
    }
    
    function outRadioInput(s_id_fp, s_onclick_fp, s_value_fp, s_name_fp) {
    	var s_html = HTML_RADIOINPUT;
    	s_html = s_html.replace(RGX_ID, s_id_fp);
    	s_html = s_html.replace(RGX_ONCLICK, s_onclick_fp);
    	s_html = s_html.replace(RGX_VALUE, s_value_fp);
    	s_html = s_html.replace(RGX_NAME, s_name_fp);
    	return s_html;
    }

    function outSingleFieldInput(m_value_fp) {
        var s_input1;
        var s_falseact;
        var s_trueact;
        s_trueact = s_objname + HTML_MTHCLRELE.replace(RGX_ID,s_submitdivid);
        s_falseact = s_objname + HTML_MTHOUTSUBLNK;
        s_onkeyup = outSelfCondChng("''",s_trueact,s_falseact);
        s_input1 = outTextInput(DEF_IDCONF1TXT,i_size,i_maxlen,s_onkeyup,m_value_fp);
        doUpdateElement(s_input1divid,s_input1);
    }

    function outStateSelect() {
        var i_index;
        var i_countryid = getInputValue(DEF_IDCOUNTRYSEL);
        var s_opts;
        //write the initial label line selector
        s_opts = outSelectOption(DEF_NONSELECT,a_lang[KEY_REG][KEY_LBLSTATE]);
        //write the list of days
        for (i_index in a_statelist[i_countryid]) {
            s_opts += outSelectOption(a_statelist[i_countryid][i_index]['state_id'],a_statelist[i_countryid][i_index]['local_name']);
        }
        //write the full input element
        //set the onchange to blank out submit if label option is selected, show submit if not
        s_formselect = outSelect(DEF_IDSTATESEL,s_opts,outSubmitSelOnChng());
        //update the element on the page
        doUpdateElement(s_statedivid,s_formselect);
    }

    function outSubmitLink() {
        var s_link = HTML_SUBMITLINK;
        s_link = s_link.replace(RGX_ONCLICK,s_submitact);
        s_link = s_link.replace(RGX_SUBMIT,a_lang[KEY_REG][KEY_LBLSUBMIT]);
        doUpdateElement(s_submitdivid,s_link);
    }

    function outTextInput(s_eleid_fp,i_fieldsize_fp,i_maxlen_fp,s_onkeyup_fp,s_value_fp) {
        var s_textfield = HTML_TEXTINPUT;
        if (!s_value_fp) {
            s_value_fp = '';
        }
        s_textfield = s_textfield.replace(RGX_ID, s_eleid_fp);
        s_textfield = s_textfield.replace(RGX_SIZE, i_fieldsize_fp);
        s_textfield = s_textfield.replace(RGX_MAXLEN, i_maxlen_fp);
        s_textfield = s_textfield.replace(RGX_ONKEYUP, s_onkeyup_fp);
        s_textfield = s_textfield.replace(RGX_VALUE, s_value_fp);
        s_textfield = s_textfield.replace(RGX_TYPE, s_fieldtype);
        return s_textfield;
    }

    function outYearSelect() {
        var i_loop;
        var s_falseaction;
        var s_formselect;
        var s_onchange;
        var s_opts;
        var s_trueaction;
        //write the initial label line selector
        s_opts = outSelectOption(DEF_NONSELECT,a_lang[KEY_REG][KEY_LBLYEAR]);
        //write the actual value lines
        for (i_loop = i_maxyear; i_loop >= i_minyear; i_loop--) {
            s_opts += outSelectOption(i_loop,i_loop);
        }
        //set the onchange to blank out month & day if label option is selected, show month if not
        s_trueaction = s_objname + HTML_MTHCLRELE.replace(RGX_ID,s_submitdivid);
        s_trueaction += s_objname + HTML_MTHCLRELE.replace(RGX_ID,s_daydivid);
        s_trueaction += s_objname + HTML_MTHCLRELE.replace(RGX_ID,s_monthdivid);
        s_falseaction = s_objname + HTML_MTHOUTMNTHSEL;
        s_falseaction += s_objname + HTML_MTHCLRELE.replace(RGX_ID,s_submitdivid);
        s_onchange = outSelfCondChng("'" + DEF_NONSELECT + "'",s_trueaction,s_falseaction);
        //write the full input element
        s_formselect = outSelect(DEF_IDYEARSEL,s_opts,s_onchange);
        //if day was up, blank it out
        doUpdateElement(s_daydivid,'');
        //if the month was up, black it out
        doUpdateElement(s_monthdivid,'');
        //then send the year selector
        doUpdateElement(s_yeardivid,s_formselect);
    }

    function setCheckbox(s_cboxdivid_fp,s_submitdivid_fp,s_submitact_fp,s_langkey1_fp,s_langkey2_fp,s_nameroot_fp) {
        s_cboxdivid = s_cboxdivid_fp;
        s_langkey1 = s_langkey1_fp;
        s_langkey2 = s_langkey2_fp;
        s_nameroot = s_nameroot_fp;
        //s_submitdivid_fp must be explicitly set to '' to supress link's display
        s_submitdivid = s_submitdivid_fp;
        s_submitact = s_submitact_fp;
    }

    function setConfirmedFieldInput(s_fieldtype_fp,s_input1divid_fp,s_input2divid_fp,s_submitdivid_fp,s_submitact_fp,i_size_fp,i_maxlen_fp,s_langkey1_fp,s_langkey2_fp) {
        i_size = i_size_fp;
        i_maxlen = i_maxlen_fp;
        s_input1divid = s_input1divid_fp;
        s_input2divid = s_input2divid_fp;
        s_langkey1 = s_langkey1_fp;
        s_langkey2 = s_langkey2_fp;
        s_submitdivid = s_submitdivid_fp;
        s_submitact = s_submitact_fp;
        s_fieldtype = s_fieldtype_fp;
    }

    function setDateSelect(s_yeardivid_fp,s_monthdivid_fp,s_daydivid_fp,s_submitdivid_fp,s_submitact_fp,i_minyear_fp,i_maxyear_fp) {
        i_maxyear = i_maxyear_fp;
        i_minyear = i_minyear_fp;
        s_daydivid = s_daydivid_fp;
        s_monthdivid = s_monthdivid_fp;
        s_submitdivid = s_submitdivid_fp;
        s_submitact = s_submitact_fp;
        s_yeardivid = s_yeardivid_fp;
    }

    function setGenderSelect(s_genderdivid_fp,s_submitdivid_fp,s_submitact_fp) {
        s_genderdivid = s_genderdivid_fp;
        s_submitdivid = s_submitdivid_fp;
        s_submitact = s_submitact_fp;
    }

    function setLoginInput(s_input1divid_fp,s_input2divid_fp,s_submitdivid_fp,s_submitact_fp,i_size_fp,i_maxlen_fp) {
        i_size = i_size_fp;
        i_maxlen = i_maxlen_fp;
        s_input1divid = s_input1divid_fp;
        s_input2divid = s_input2divid_fp;
        s_submitdivid = s_submitdivid_fp;
        s_submitact = s_submitact_fp;
    }

    function setSingleFieldInput(s_fieldtype_fp,s_input1divid_fp,s_submitdivid_fp,s_submitact_fp,i_size_fp,i_maxlen_fp) {
        i_size = i_size_fp;
        i_maxlen = i_maxlen_fp;
        s_input1divid = s_input1divid_fp;
        s_submitdivid = s_submitdivid_fp;
        s_submitact = s_submitact_fp;
        s_fieldtype = s_fieldtype_fp;
    }

    function setRegionSelect(s_countrydivid_fp,s_statedivid_fp,s_submitdivid_fp,s_submitact_fp) {
        s_countrydivid = s_countrydivid_fp;
        s_statedivid = s_statedivid_fp;
        s_submitdivid = s_submitdivid_fp;
        s_submitact = s_submitact_fp;
    }

    function setSubmitLink(s_submitdivid_fp,s_submitact_fp) {
        s_submitdivid = s_submitdivid_fp;
        s_submitact = s_submitact_fp;
    }

    function setTextInput(s_fieldtype_fp) {
        s_fieldtype = s_fieldtype_fp;
    }

    //private methods
    function doLoadTracker() {
        a_loadtracker[KEY_COMPLETE]++;
        if (a_loadtracker[KEY_COMPLETE] === a_loadtracker[KEY_REQUEST]) {
            //alert(' form ready');
            f_formready();
        }
    }

    function doUpdateElement(s_eleid_fp,s_content_fp) {
        document.getElementById(s_eleid_fp).innerHTML = s_content_fp;
    }

    function doValidatePattern(s_haystack_fp,s_needles_fp) {
        if (s_needles_fp.test(s_haystack_fp) !== true) {
            return false;
        }
        return true;
    }

    function getBadwords(s_cusspath_fp) {
        if (s_cusspath_fp != '') {
            a_loadtracker[KEY_REQUEST]++;

		$.post( "?request=loadbadwords" , function( http ) { 
					 setBadwords( eval( "(" + http + ")" ) ); 
		} );
        }
    }

    function getCountryList(s_countrylistpath_fp) {
        if (s_countrylistpath_fp != '') {
            //var o_ajaxreq5 = new ajaxReq('o_ajaxreq5');
            a_loadtracker[KEY_REQUEST]++;
            //o_ajaxreq5.doServerRequest(s_countrylistpath_fp,'',setCountryList);
	    setCountryList();
        }
    }

    function getForm(s_langpath_fp) {
        if (s_langpath_fp != '') {
            //var o_ajaxreq2 = new ajaxReq('o_ajaxreq2');
            a_loadtracker[KEY_REQUEST]++;
            //o_ajaxreq2.doServerRequest(s_langpath_fp,'',setForm);
		setTimeout( function(){ setForm(); } , 500 );
        }
    }

    function getStateList(s_statelistpath_fp) {
        if (s_statelistpath_fp != '') {
            //var o_ajaxreq4 = new ajaxReq('o_ajaxreq4');
            a_loadtracker[KEY_REQUEST]++;
            //o_ajaxreq4.doServerRequest(s_statelistpath_fp,'',setStateList);
		setStateList();
        }
    }

    function getTime(s_timepath_fp) { //currently only gets yyyy-mm-dd
        if (s_timepath_fp != '') {
           // var o_ajaxreq3 = new ajaxReq('o_ajaxreq3');
            a_loadtracker[KEY_REQUEST]++;
           // o_ajaxreq3.doServerRequest(s_timepath_fp,'',setTime);
		setTime();
        }
    }

    function out2WayCondChng(s_eleid1_fp,s_ele2id_fp,s_trueact_fp,s_falseact_fp) {
        var s_onchange = HTML_CONDEVAL2ELE;
        s_onchange = s_onchange.replace(RGX_ID1,s_eleid1_fp);
        s_onchange = s_onchange.replace(RGX_ID2,s_ele2id_fp);
        s_onchange = s_onchange.replace(RGX_TRUEACT,s_trueact_fp);
        s_onchange = s_onchange.replace(RGX_FLSEACT,s_falseact_fp);
        return s_onchange;
    }

    function outAge(d_date_fp) {
        var i_rawage = Date.UTC(d_now.getFullYear(),d_now.getMonth(),d_now.getDate(),0,0,0) - Date.UTC(d_date_fp.getFullYear(),d_date_fp.getMonth(),d_date_fp.getDate(),0,0,0);
        return i_rawage/1000/60/60/24/365;
    }

    function outCheckbox(s_label_fp, i_position_fp, i_checked_fp) {
        var s_cbox = HTML_CBOXINPUT;
        var s_checked = '';
        s_cbox = s_cbox.replace(RGX_ID1, HTML_DIVELEPREFIX + s_nameroot + i_position_fp);
        if (i_checked_fp === 1) {
            s_checked = HTML_CHECKED;
        }
        s_cbox = s_cbox.replace(RGX_CHECKED, s_checked);
        s_cbox = s_cbox.replace(RGX_ID2, HTML_INPUTPREFIX + s_nameroot + i_position_fp + HTML_CBOXSUFFIX);
        s_cbox = s_cbox.replace(RGX_LABEL, s_label_fp);
        return s_cbox;
    }

    function outDate(s_date_fp) { //string MUST be yyyy-m-d with 4-digit year and hyphen separator
        var d_tmp = new Date();
        var a_date = s_date_fp.split(DEF_DATESEP);
        d_tmp.setYear(a_date[0]);
        d_tmp.setMonth(a_date[1]);
        d_tmp.setDate(a_date[2]);
        return d_tmp;
    }

    function outSelfCondChng(m_value_fp,s_trueact_fp,s_falseact_fp) {
        //m_value_fp can be any type, including quotes if it's a string
        var s_onchange = HTML_CONDEVALSELF;
        s_onchange = s_onchange.replace(RGX_VALUE,m_value_fp);
        s_onchange = s_onchange.replace(RGX_TRUEACT,s_trueact_fp);
        s_onchange = s_onchange.replace(RGX_FLSEACT,s_falseact_fp);
        return s_onchange;
    }

    function outSelect(s_eleid_fp,s_seloptions_fp,s_onchange_fp) {
        var s_select = HTML_SELECT;
        //pop all of the option lines into the full form selector
        s_select = s_select.replace(RGX_ID, s_eleid_fp);
        s_select = s_select.replace(RGX_OPTION, s_seloptions_fp);
        s_select = s_select.replace(RGX_ONCHANGE, s_onchange_fp);
        return s_select;
    }

    function outSelectOption(s_value_fp,s_option_fp) {
        var s_seloption = HTML_SELECTOPTION;
        s_seloption = s_seloption.replace(RGX_VALUE, s_value_fp);
        s_seloption = s_seloption.replace(RGX_OPTION, s_option_fp);
        return s_seloption;
    }

    function outSubmitSelOnChng() {
        var s_falseaction;
        var s_onchange;
        var s_trueaction;
        s_trueaction = s_objname + HTML_MTHCLRELE.replace(RGX_ID,s_submitdivid);
        s_falseaction = s_objname + HTML_MTHOUTSUBLNK;
        s_onchange = outSelfCondChng("'" + DEF_NONSELECT + "'",s_trueaction,s_falseaction);
        return s_onchange;
    }

    function setBadwords(a_cuss_fp) {
        a_cuss = a_cuss_fp;
        doLoadTracker();
    }

    function setCallback(s_objname_fp) {
        s_objname = s_objname_fp;
    }

    function setCountryList(a_countrylist_fp) {
        a_countrylist = moxieHash.countryList;
        doLoadTracker();
    }

    function setForm(a_lang_fp) { //called from an external ajax request to get all lang for form interfaces
	a_lang = moxieHash.language;
        doLoadTracker();
    }

    function setLoadTracker() {
        a_loadtracker = new Array();
        a_loadtracker[KEY_REQUEST] = 0;
        a_loadtracker[KEY_COMPLETE] = 0;
    }

    function setStateList(a_statelist_fp) {
	a_statelist = moxieHash.stateList
        doLoadTracker();
    }

    function setTime(d_now_fp) {
        d_now = outDate( currentDate );
        doLoadTracker();
    }
}

