﻿function namespace(namespaceString){
	var parts = namespaceString.split('.')
		,parent = window
		,currentPart = '';
	for (var i = 0; i < parts.length; i++){
		currentPart = parts[i];
		parent[currentPart] = parent[currentPart] || {};
		parent = parent[currentPart];
	}
	return parent;
};

var Common = {
    Testing: false,  // windows open normally when true
    ShowErrors: false, // js alerts on exceptions when true
    //########################################################################
    //                     W I N D O W
    //########################################################################
    Window: {
        // window.open(url, windowName, directories=0|1,status=0|1,toolbar=0|1,location=0|1,menubar=0|1,resizable=0|1,scrollbars=0|1,height=pixels,width=pixels);
        // opens a window using the passed attribute string
        Open: function(url, name, attributes) {
            if (!name)
                name = '';
            if (attributes && attributes != "")
                return window.open(url, name, attributes);
            else
                return window.open(url, name);
        },
        // opens a DEFAULT SIZED window with all attributes enabled (less directories)
        OpenNormal: function(url, name) {
            return Common.Window.OpenCustom(url, name, 0, 1, 1, 1, 1, 1, 1, 1);
        },
        // opens a window with all attributes enabled (less directories)
        OpenSizedNormal: function(url, name, height, width, top, left) {
            var handle = Common.Window.OpenCustom(url, name, 0, 1, 1, 1, 1, 1, 1, 1, height, width);
            if (handle != null && left != null && top != null)
                handle.moveTo(left, top);
            return handle;
        },
        // opens a window with the passed attributes specified
        OpenCustom: function(url, name, dependent, directories, location, menubar, resizable, scrollbars, status, toolbar, height, width) {
            var attributes = 'dependent=' + dependent +
							', directories=' + directories +
							', location=' + location +
							', menubar=' + menubar +
							', resizable=' + resizable +
							', scrollbars=' + scrollbars +
							', status=' + status +
							', toolbar=' + toolbar;
            if (height != null)
                attributes += ', height=' + height;
            if (width != null)
                attributes += ', width=' + width;

            return window.open(url, name, attributes);
        },
        // opens a resizeable window
        OpenBorderless: function(url, name, height, width, top, left) {
            var handle = Common.Window.OpenCustom(url, name, 0, 0, 0, 0, 1, 0, 0, 0, height, width);
            if (handle != null && left != null && top != null)
                handle.moveTo(left, top);
            return handle;
        },
        // opens a resizeable window with scrollbars
        OpenBorderlessScrolling: function(url, name, height, width, top, left) {
            var handle = Common.Window.OpenCustom(url, name, 0, 0, 0, 0, 1, 1, 0, 0, height, width);
            if (handle != null && left != null && top != null)
                handle.moveTo(left, top);
            return handle;
        },
        // returns a string of various window setting information
        GetInfo: function() {
            var s = 'HEIGHT:';
            if (window.innerHeight != null) s += '\n window.innerHeight = ' + window.innerHeight;
            if (window.outerHeight != null) s += '\n window.outerHeight = ' + window.outerHeight;
            if (document.body.clientHeight != null) s += '\n document.body.clientHeight = ' + document.body.clientHeight;
            if (document.body.offsetHeight != null) s += '\n document.body.offsetHeight = ' + document.body.offsetHeight;
            if (document.documentElement.clientHeight != null) s += '\n document.documentElement.clientHeight = ' + document.documentElement.clientHeight;
            if (document.documentElement.offsetHeight != null) s += '\n document.documentElement.offsetHeight = ' + document.documentElement.offsetHeight;
            s += '\n GetClientHeight() = ' + Common.Window.GetClientHeight();
            if (window.screen.availHeight) s += '\n window.screen.availHeight = ' + window.screen.availHeight;
            if (window.screen.height) s += '\n window.screen.height = ' + window.screen.height;

            s += '\n\nWIDTH:';
            if (window.innerWidth != null) s += '\n window.innerWidth = ' + window.innerWidth;
            if (window.outerWidth != null) s += '\n window.outerWidth = ' + window.outerWidth;
            if (document.body.clientWidth != null) s += '\n document.body.clientWidth = ' + document.body.clientWidth;
            if (document.body.offsetWidth != null) s += '\n document.body.offsetWidth = ' + document.body.offsetWidth;
            if (document.documentElement.clientWidth != null) s += '\n document.documentElement.clientWidth = ' + document.documentElement.clientWidth;
            if (document.documentElement.offsetWidth != null) s += '\n document.documentElement.offsetWidth = ' + document.documentElement.offsetWidth;
            s += '\n GetClientWidth() = ' + Common.Window.GetClientWidth();
            if (window.screen.availWidth) s += '\n window.screen.availWidth = ' + window.screen.availWidth;
            if (window.screen.width) s += '\n window.screen.width = ' + window.screen.width;

            s += '\n\nTOP:';
            if (window.screenY != null) s += '\n window.screenY = ' + window.screenY;
            if (window.screenTop != null) s += '\n window.screenTop = ' + window.screenTop;
            s += '\n GetClientTop() = ' + Common.Window.GetClientTop();
            if (window.screen.top) s += '\n window.screen.top = ' + window.screen.top;
            if (window.screen.availTop) s += '\n window.screen.availTop = ' + window.screen.availTop;

            s += '\n\nLEFT:';
            if (window.screenX != null) s += '\n window.screenX = ' + window.screenX;
            if (window.screenLeft != null) s += '\n window.screenLeft = ' + window.screenLeft;
            s += '\n GetClientLeft() = ' + Common.Window.GetClientLeft();
            if (window.screen.left) s += '\n window.screen.left = ' + window.screen.left;
            if (window.screen.availLeft) s += '\n window.screen.availLeft = ' + window.screen.availLeft;

            return s;
        },
        // returns the window's top position plus the passed offset
        GetClientTop: function(offset) {
            var top = 0;
            if (window.screenY)
                top = window.screenY;
            else if (window.screenTop)
                top = window.screenTop;
            if (offset != null && offset != Number.NaN)
                top = top + offset;
            return top;
        },
        // returns the window's left position plus the passed offset
        GetClientLeft: function(offset) {
            var left = 0;
            if (window.screenX)
                left = window.screenX;
            else if (window.screenLeft)
                left = window.screenLeft;
            if (offset != null && offset != Number.NaN)
                left = left + offset;
            return left;
        },
        // returns the window width plus the passed offset
        GetClientWidth: function(offset) {
            var width = 0;
            // for FF, inner width includes the dynamic scroll bars
            if (window.innerWidth)
                width = window.innerWidth;
            // for IE, scroll bars become disabled, so it's a part of the offset
            else if (document.documentElement.clientWidth)
                width = document.documentElement.clientWidth;
            if (offset != null && offset != Number.NaN)
                width = width + offset;
            return width;
        },
        // returns the window height plus the passed offset
        GetClientHeight: function(offset) {
            var height = 0;
            // for FF, inner height includes the dynamic scroll bars
            if (window.innerHeight)
                height = window.innerHeight;
            // for IE, scroll bars become disabled, so it's a part of the offset
            else if (document.documentElement.clientHeight)
                height = document.documentElement.clientHeight;
            if (offset != null && offset != Number.NaN)
                height = height + offset;
            return height;
        }
    },

    //########################################################################
    //                          D I S P L A Y
    //########################################################################
    Display: {
        Hide: function(object) {
            if (object == null) return;
            object.style.display = 'none';
        },
        ShowBlock: function(object) {
            if (object == null) return;
            object.style.display = 'block';
        },
        ShowInline: function(object) {
            if (object == null) return;
            object.style.display = 'inline';
        }
    },

    //########################################################################
    //                          T O G G L E
    //########################################################################
    Toggle: {
        // toggles the display of the passed element between none and block
        DisplayBlock: function(object) {
            if (object == null) return;
            object.style.display = (object.style.display == 'block' || object.style.display == '') ? 'none' : 'block';
            return (object.style.display == 'block');
        },
        // toggles the display of the passed element between none and inline
        DisplayInline: function(object) {
            if (object == null) return;
            object.style.display = (object.style.display == 'inline' || object.style.display == '') ? 'none' : 'inline';
            return (object.style.display == 'inline');
        },
        // toggles the passed class of the passed element
        Class: function(element, classname) {
            if (!Common.Class.Contains(element, classname))
                Common.Class.Add(element, classname);
            else
                Common.Class.Remove(element, classname);
        },
        // toggles the visibility of the passed element
        Visibility: function(element) {
            if (element == null) return;
            element.style.visibility = (element.style.visibility == '' || element.style.visibility == 'visible') ? 'hidden' : 'visible';
        },
        // toggles the disabled attribute of the passed element
        Disabled: function(object) {
            if (object == null) return;
            object.disabled = (object.disabled) ? '' : 'disabled';
        },
        Sibling: function(sender, siblingTag) {
            var node = Common.DOM.GetValidNextSibling(sender);
            if (node.nodeName == siblingTag) {
                Common.Toggle.DisplayBlock(node);
            }
        }

    },

    //########################################################################
    //                        D O M
    // some DOM nodes are empty
    // these get valid nodes
    //########################################################################
    DOM: {
        // returns the first valid child node of the passed element
        GetValidChildNode: function(sender) {
            try {
                if (!sender.hasChildNodes()) return null;
                var node = sender.childNodes[0];
                while ((node != null) && (node.nodeType != 1)) {
                    node = node.nextSibling;
                }
                return node;
            } catch (err) { Common.Except(err, 'Common.DOM.GetValidChildNode'); }
        },
        // returns the valid previous sibling of the passed element
        GetValidPreviousSibling: function(sender) {
            try {
                var node = sender.previousSibling;
                while ((node != null) && (node.nodeType != 1)) {
                    node = node.previousSibling;
                }
                return node;
            } catch (err) { Common.Except(err, 'Common.DOM.GetValidPreviousSibling'); }
        },
        // returns the valid next sibling of the passed element
        GetValidNextSibling: function(sender) {
            try {
                var node = sender.nextSibling;
                while ((node != null) && (node.nodeType != 1)) {
                    node = node.nextSibling;
                }
                return node;
            } catch (err) { Common.Except(err, 'Common.DOM.GetValidNextSibling'); }
        }
    },

    //########################################################################
    //                        S E L E C T
    //########################################################################
    Select: {
        // returns the value of the selected index
        SelectedValue: function(element) {
            var result = '';
            try {
                result = element.options[element.selectedIndex].value;
            } catch (err) { Common.Except(err, 'Common.Select.SelectedValue'); }
            return result;
        },
        // returns the text of the selected index
        SelectedText: function(element) {
            var result = '';
            try {
                result = element.options[element.selectedIndex].text;
            } catch (err) { Common.Except(err, 'Common.Select.SelectedText'); }
            return result;
        },
        // returns an array of option objects
        SelectedOptionsAsArray: function(element) {
            var result = [];
            try {
                for (var i = 0; i < element.options.length; i++) {
                    var option = element.options[i];
                    if (option.selected)
                        result.push(option);
                }
            } catch (err) { Common.Except(err, 'Common.Select.SelectedOptionsAsArray'); }
            return result;
        },
        // returns an array of selected options.value
        SelectedValuesAsArray: function(element) {
            var result = [];
            try {
                for (var i = 0; i < element.options.length; i++) {
                    var option = element.options[i];
                    if (option.selected)
                        result.push(option.value);
                }
            } catch (err) { Common.Except(err, 'Common.Select.SelectedValuesAsArray'); }
            return result;
        },
        // populates a select element with an array of text (no values are added)
        PopulateWithArray: function(element, array) {
            Common.Select.Options.Clear(element);
            if (array.length == 0) return;
            for (var i = 0; i < array.length; i++) {
                Common.Select.Options.Add(element, array[i], null, i);
            }
        },

        //########################################################################
        //                      S E L E C T . O P T I O N S
        //########################################################################
        Options: {
            // adds an option with the passed attributes to the passed select element at the passed index
            // will add to the end of the option list if index is not specified
            Add: function(element, text, value, index) {
                if (element == null) return;

                if (index == null || index < -1 || index >= element.options.length)
                    index = element.options.length;

                if (typeof index != 'number')
                    index = Common.ParseInt(index);

                var opt = document.createElement('option');
                if (text != null && text != '')
                    opt.text = text;
                if (value != null && text != '')
                    opt.value = value;
                element.options.add(opt, index);
            },
            // adds an option element to the passed select element at the passed index
            // will add to the end of the option list if index is not specified
            AddOption: function(element, option, index) {
                if (!element || !option) return;
                if (index == null || index < -1 || index >= element.options.length)
                    index = element.options.length;

                if (typeof index != 'number')
                    index = Common.ParseInt(index);
                
                //The "option" argument may not not actually be an Option
                try {
                    element.options.add(option, index);
                }
                catch (err) {
                    element.options.add(new Option(option.text, option.value), index);
                }

            },
            // adds option elements contained in an array to the passed select element starting at the passed index
            AddOptionArray: function(element, options, index) {
                if (!element || !options) return;
                for (var i = 0; i < options.length; i++)
                    Common.Select.Options.AddOption(element, options[i], index);
            },
            RemoveOptionArray: function(element, options) {
                if (!element || !options) return;
                for (var i = 0; i < options.length; i++)
                    Common.Select.Options.RemoveOption(element, options[i]);
            },
            RemoveOption: function(element, option) {
                if (!element || !option) return;
                for (var i = 0; i < element.options.length; i++) {
                    var candidate = element.options[i]
                    if (candidate.text == option.text && candidate.value == option.value)
                        element.remove(i);
                }
            },
            // removes the option with the specified index
            // if question is populated, prompts the user for confirmation
            Remove: function(element, index, question) {
                if (element == null) return;
                if (element.length == -1) return;

                if (index == null)
                    index = element.selectedIndex;
                if (index == -1) return;
                if (question != null && question != '') {
                    //if (confirm(question + ' ' + element.options[index].text + '?')){
                    if (confirm(Common.Format(question, element.options[index].text))) {
                        element.remove(index);
                    }
                }
                else {
                    element.remove(index);
                }
            },
            // removes all options from a select element
            Clear: function(element) {
                if (element != null && element.options != null)
                    while (element.options.length > 0)
                    Common.Select.Options.Remove(element, 0);
            },
            // returns an array of options.value
            ValuesAsArray: function(element, sort) {
                var result = [];
                if (element.options.length > 0) {
                    for (var i = 0; i < element.options.length; i++)
                        result.push(element.options[i].value);
                    if (sort)
                        result.sort();
                }
                return result;
            },
            // returns an array of options.text
            TextAsArray: function(element, sort) {
                var result = [];
                if (element.options.length > 0) {
                    for (var i = 0; i < element.options.length; i++)
                        result.push(element.options[i].text);
                    if (sort)
                        result.sort();
                }
                return result;
            }
        }
    },

    //########################################################################
    //                        C L A S S
    //########################################################################
    Class: {
        // returns an array of elements with a given class and tagname
        Find: function(classname, tagname, source) {
            var result = [];
            if (!source)
                source = document;
            var elements = source.getElementsByTagName(tagname);
            for (var i = 0; i < elements.length; i++) {
                var element = elements[i];
                if (Common.Class.Contains(element, classname))
                    result.push(element);
            }
            return result;
        },
        // adds or removes a class to an element
        Set: function(element, classname, enable) {
            if (!element) return;
            if (enable)
                Common.Class.Add(element, classname);
            else
                Common.Class.Remove(element, classname);
        },
        // returns an array of an element's class names
        AsArray: function(element) {
            var result = [];
            if (element) {
                result = element.className.split(' ');
            }
            return result;
        },
        // replaces one class name with another
        Replace: function(element, fromclass, toclass) {
            if (element) {
                var classnames = Common.Class.AsArray(element);
                if (classnames.indexOf(fromclass) > -1)
                    Common.RemoveArrayItem(classnames, fromclass);
                if (classnames.indexOf(toclass) == -1)
                    classnames.push(toclass);
                element.className = classnames.join(' ');
            }
        },
        // returns true if the element has the class name
        Contains: function(element, classname) {
            return (Common.Class.AsArray(element).indexOf(classname) > -1);
            //return (element.className.indexOf(classname) > -1);
        },
        // adds a class name to an element
        Add: function(element, classname) {
            if (element) {
                var classnames = Common.Class.AsArray(element);
                if (classnames.indexOf(classname) == -1)
                    classnames.push(classname);
                element.className = classnames.join(' ');
            }
        },
        // removes a class name to an element
        Remove: function(element, classname) {
            if (element) {
                var classnames = Common.Class.AsArray(element);
                if (classnames.indexOf(classname) > -1)
                    Common.RemoveArrayItem(classnames, classname);
                element.className = classnames.join(' ');
            }
        }
    },

    //########################################################################
    //                       K E Y
    // all methods should be assigned as an onkeypress event handler
    //########################################################################
    Key: {
        // returns the key code of the key pressed
        GetCode: function(e) {
            var code;
            if (window.event)
                code = window.event.keyCode;
            else if (e && e.which)
                code = e.which;
            else if (e && e.keyCode)
                code = e.keyCode;
            return code;
        },
        // returns true if the shift key was held during a key press
        UsingShift: function(e) {
            var result = false;
            if (window.event)
                result = window.event.shiftKey;
            else if (e && e.shiftKey)
                result = e.shiftKey;
            return result;
        },
        // returns true if the ctrl key was held during a key press
        UsingCtrl: function(e) {
            var result = false;
            if (window.event)
                result = window.event.ctrlKey;
            else if (e && e.ctrlKey)
                result = e.ctrlKey;
            return result;
        },
        // returns true if the alt key was held during a key press
        UsingAlt: function(e) {
            var result = false;
            if (window.event)
                result = window.event.altKey;
            else if (e && e.altKey)
                result = e.altKey;
            return result;
        }
    },

    //########################################################################
    //                       S T R I N G
    //########################################################################
    String: {
        // analog of C# String.Replace; replaces all occurrences of the oldValue with newValue
        // the native JS version only replaces the first occurrence.
        // uses JS regular expressions so forward slashes must be escaped / -> \/
        ReplaceAll: function(text, oldValue, newValue) {
            alert('You are the first to use this function. Make sure it works.');
            var re = new RegExp(oldValue, 'g');
            return text.replace(re, newValue);
        },
        // Analog of C# String.Format
        Format: function(str) {
            if (arguments.length == 0) return '';
            var result = str;
            for (var i = 0; i < arguments.length; i++) {
                var re = new RegExp('\\{' + (i) + '\\}', 'gm');
                result = result.replace(re, arguments[i + 1]);
            }
            return result;
        },
        Chop: function(str, from, to) {
            var result = str;
            var f = str.indexOf(from) + from.length;
            result = str.substring(f, str.indexOf(to, f));
            return result;
        }
    },
    //########################################################################
    //                         C U R S O R
    //########################################################################
    Cursor: {
        // returns the cursor's location as a point
        Position: function(e) {
            var result = { x: 0, y: 0 };
            if (!e)
                var e = window.event;
            if (e.pageX || e.pageY) {
                result.x = e.pageX;
                result.y = e.pageY;
            }
            else if (e.clientX || e.clientY) {
                result.x = e.clientX;
                result.y = e.clientY;
            }
            return result;
        }
    },
    //########################################################################

    // Appends an event handler -- foo.onclick = Common.AddEventHandler(foo.onclick, newhandler);
    AddEventHandler: function(e, x) {
        return function() { if (e) e(); x(); };
    },
    // assigns events to passed element to prevent the selection of text
    DisableTextSelection: function(elementid) {
        var obj = document.getElementById(elementid);
        if (obj == null) return;
        obj.onselectstart = function() { return false; }
        obj.onmousedown = function() { return false; }
    },
    // returns an integer representation of the passed string
    ParseInt: function(string) {
        var number = parseInt(string);
        if (number == Number.NaN)
            number = 0;
        return number;
    },
    // removes the first instance of the passed item from the passed array
    RemoveArrayItem: function(array, item) {
        var index = array.indexOf(item);
        if (index > -1)
            array.splice(index, 1);
        return index;
    },
    // adds an "alt" class to all even rows in a table's tbody section (required)
    StripeTable: function(element) {
        if (element == null) return;
        var tbodies = element.getElementsByTagName('tbody');
        for (var i = 0; i < tbodies.length; i++) {
            var trs = tbodies[i].getElementsByTagName('tr');
            for (var j = 0; j < trs.length; j++) {
                if (j % 2 == 1)
                    Common.Class.Set(trs[j], 'alt', true);
            }
        }
    },
    // applies Common.StripeTable() to all tables with a "data" class
    StripeDataTables: function() {
        var tables = document.getElementsByTagName('table');
        for (var i = 0; i < tables.length; i++) {
            if (!Common.Class.Contains(tables[i], 'data')) continue;
            Common.StripeTable(tables[i]);
        }
    },
    // stripes tables according to the current AgencyTemplate
    StripeTableAgencyStyle: function(boardbodyDocument) {
        var tables = boardbodyDocument.getElementsByTagName('table');
        for (var j = 0; j < tables.length; j++) {
            var trs = tables[j].getElementsByTagName('tr');
            for (var i = 0; i < trs.length; i++) {
                if (Common.Class.Contains(trs[i], 'agencytemplate_tableentry')) {
                    Common.Class.Add(trs[i], (i % 2 == 0) ? 'agencytemplate_tableroweven' : 'agencytemplate_tablerowodd');
                }
            }
        }
    },
    // returns true if json.js has not been included in the page
    JSONMethodsUnavailable: function() {
        return (!String.prototype.parseJSON && !JSON);
    },
    // Returns the class name of the argument or undefined if it's not a valid JavaScript object.
    GetObjectClass: function(obj) {
        if (obj && obj.constructor && obj.constructor.toString) {
            var arr = obj.constructor.toString().match(/function\s*(\w+)/);
            if (arr && arr.length == 2)
                return arr[1];
        }
        return undefined;
    },
    // Analog of String.Format
    Format: function(str) {
        if (arguments.length == 0) return '';
        var result = str;
        for (var i = 0; i < arguments.length; i++) {
            var re = new RegExp('\\{' + (i) + '\\}', 'gm');
            result = result.replace(re, arguments[i + 1]);
        }
        return result;
    },
    // Sets an element to be enabled or disabled
    Disable: function(element, disable) {
        if (!element) return;
        if (disable)
            element.disabled = 'disabled';
        else
            element.disabled = '';
    },
    ContainsChecked: function(array) {
        var result = false;
        for (var i = 0; i < array.length; i++) {
            if (array[i].checked) {
                result = true;
                break;
            }
        }
        return result;
    },
    // alerts the user with an error description
    Except: function(err, caller) {
        if (Common.ShowErrors)
            alert('Error: ' + err.description + '\nCalled By: ' + caller);
    },
    // returns the sender of an event
    Sender: function(e) {
        var result = null;
        if (!e) {
            e = window.event;
        }
        if (e.target) {
            result = e.target;
        }
        else if (e.srcElement) {
            result = e.srcElement;
        }
        if (result.nodeType == 3) { // defeat Safari bug
            result = result.parentNode;
        }
        return result;
    }
}
// Adds indexOf property to arrays for pathetic browsers that haven't fully implemented JavaScript 1.5 yet
// from http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf#Compatibility
//if (!Array.prototype.indexOf){
//  Array.prototype.indexOf = function(elt /*, from*/){
//    var len = this.length;
//    var from = Number(arguments[1]) || 0;
//    from = (from < 0) ? Math.ceil(from) : Math.floor(from);
//    if (from < 0)
//      from += len;
//    for (; from < len; from++){
//      if (from in this && this[from] === elt)
//        return from;
//    }
//    return -1;
//  };
//}
// Adds indexOf property to Arrays for browsers that haven't implemented JS 1.6
// from http://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf#Compatibility
    if (!Array.prototype.indexOf) {
        Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
            "use strict";
            if (this === void 0 || this === null) {
                throw new TypeError();
            }
            var t = Object(this);
            var len = t.length >>> 0;
            if (len === 0) {
                return -1;
            }
            var n = 0;
            if (arguments.length > 0) {
                n = Number(arguments[1]);
                if (n !== n) { // shortcut for verifying if it's NaN
                    n = 0;
                } else if (n !== 0 && n !== Infinity && n !== -Infinity) {
                    n = (n > 0 || -1) * Math.floor(Math.abs(n));
                }
            }
            if (n >= len) {
                return -1;
            }
            var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
            for (; k < len; k++) {
                if (k in t && t[k] === searchElement) {
                    return k;
                }
            }
            return -1;
        }
    }

// Returns the specified substring count
if (!String.prototype.instancesOf) {
    String.prototype.instancesOf = function(characterToFind) {
        var res = this.match(new RegExp(characterToFind, "g"));
        if (res == null) { return 0; }
        return res.length;
    }
}

