
// *************************************   MICROSTRATEGY OBJECT ***********************************************
// This object is the global namespace for MicroStrategy's client-side javascript objects
// (such as bones & zones), and for global constants & functions.
// ************************************************************************************************************
//<script>

/**
 * @class Serves as the global namespace and controller for the MicroStrategy bones infrastructure.
 */
if (typeof(microstrategy) == 'undefined') {
	self.microstrategy = new function() { };
}
microstrategy.prototype = {};

//constants
microstrategy.OBJTYPE_ATTRIBUTE = 'ATTR';
microstrategy.OBJTYPE_METRIC = 'MV';
microstrategy.OBJTYPE_OBJBROWSER = 'obbr';
microstrategy.OBJTYPE_EDITOR = "edt";
microstrategy.OBJTYPE_GRAPH_ZONES = "gzn";
microstrategy.OBJTYPE_RW_PAGE = 'RWPA';
microstrategy.OBJTYPE_RW_TEXTFIELD = 'TEXT';
microstrategy.OBJTYPE_DOC = 'docu';
microstrategy.OBJTYPE_DOC_OBJECT = 'obj';
microstrategy.OBJTYPE_DOC_SUBSECTION_CONTAINER = 'subscon';
microstrategy.OBJTYPE_DOC_SUBSECTION = '4';
microstrategy.OBJTYPE_DOC_SECTION = 'dsec';
microstrategy.OBJTYPE_DOC_HORIZONTAL_CONTAINER = 'hcont';
microstrategy.OBJTYPE_DOC_PARENT_HORIZONTAL_CONTAINER = 'parenthcont';
microstrategy.OBJTYPE_DOC_SELECTION = 'dsel';
microstrategy.OBJTYPE_RW_HILITES = 'RWHI';
microstrategy.OBJTYPE_RW_HANDLES = 'RWHA';
microstrategy.OBJTYPE_RW_LASSO = 'RWLA';
microstrategy.OBJTYPE_DOCKZONE = 'dock';
microstrategy.OBJTYPE_TOOLBAR = 'tool';
microstrategy.OBJTYPE_FOLDER = 'f';
microstrategy.OBJTYPE_ATTRIBUTE = 'a';
microstrategy.OBJTYPE_ELEMENT = 'e';
microstrategy.OBJTYPE_GRID = 'g';
microstrategy.OBJTYPE_GRAPH = 'gp';
microstrategy.OBJTYPE_BTN_GROUP = 'btng';
microstrategy.OBJTYPE_PAGE_BY = 'pgby';
microstrategy.OBJTYPE_PAGE_BY_ELEM = 'pbel';
microstrategy.OBJTYPE_FAKED_PAGE_BY_ELEM = 'fkpbel';
microstrategy.OBJTYPE_FILTER_EDITOR = 'filt';
microstrategy.OBJTYPE_RULER = 'rul';
microstrategy.OBJTYPE_MASK = 'mask';
microstrategy.OBJTYPE_MASK_MAP = 'mama';
microstrategy.OBJTYPE_MASK_MAP_AREA = 'mmar';
microstrategy.OBJTYPE_ANY = '*';
microstrategy.OBJTYPE_FORMULA_BAR = 'fmla';
microstrategy.OBJTYPE_TAB = 'tab';
microstrategy.OBJTYPE_TAB_SET = 'tset';
microstrategy.OBJTYPE_INC_FETCH_PANE = 'incf';
microstrategy.OBJTYPE_INC_FETCH = 'if';
microstrategy.OBJTYPE_OBJECT_COUNT = 'objCount';
microstrategy.OBJTYPE_EDITOR = "edt";
microstrategy.OBJTYPE_CONTEXT_MENU = "cxt";
microstrategy.OBJTYPE_MESSAGE_BOX = "mbx";
microstrategy.OBJTYPE_DSEL_MOVE_RECS = "mrec";
microstrategy.OBJTYPE_FLOATING_TOOLBAR = "ftb";
microstrategy.OBJTYPE_SECURITY_FILTER = 'sf';
microstrategy.OBJTYPE_FIRST_CLASS_OBJECT = "fco";
microstrategy.OBJTYPE_XDA_DATA_ELEMENT = "xdae";
microstrategy.OBJTYPE_PANEL_STACK = "pnls";
microstrategy.OBJTYPE_SCROLLER_HANDLE = "schn";
microstrategy.OBJTYPE_SCROLLER_CONTAINER = "sctb";
microstrategy.OBJTYPE_SCROLLER_CONTAINER_GHOST = "sctbgh";
microstrategy.OBJTYPE_SCROLLER_TRACK = "sctrk";

microstrategy.ORIENTATION_HORIZONTAL = 0;
microstrategy.ORIENTATION_VERTICAL = 1;

microstrategy.GRIDCELL_ORIENTATION_VERTICAL = 'V';
microstrategy.GRIDCELL_ORIENTATION_HORIZONTAL = 'H';
microstrategy.GRIDCELL_AXIS_METRICS = -1;
microstrategy.GRIDCELL_AXIS_ATT_FORMS = 0;
microstrategy.GRIDCELL_AXIS_ROWS = 1;
microstrategy.GRIDCELL_AXIS_COLUMNS = 2;
microstrategy.GRIDCELL_AXIS_PAGE_BY = 3;

microstrategy.GRID_EFFECTIVE_VIEW_GRID = 0;
microstrategy.GRID_EFFECTIVE_VIEW_GRAPH = 1;
microstrategy.GRID_EFFECTIVE_VIEW_GRID_GRAPH = 2;

microstrategy.SUBOBJTYPE_TITLEBAR = 'titl';
microstrategy.SUBOBJTYPE_STATUSBAR = 'stat';
microstrategy.SUBOBJTYPE_TOOLBAR = 'tool';
microstrategy.SUBOBJTYPE_TOOLBAR_HANDLE = 'toha';
microstrategy.SUBOBJTYPE_GRID_TABLE = 'tabl';
microstrategy.SUBOBJTYPE_TREE = 'tree';
microstrategy.SUBOBJTYPE_TREE_VIEW = 'treeView';
microstrategy.SUBOBJTYPE_BODY = 'body';
microstrategy.SUBOBJTYPE_SECTION_HANDLE = 'shan';
microstrategy.SUBOBJTYPE_SUBSECTION_HANDLE = 'sshan';
microstrategy.SUBOBJTYPE_DOC_HTML_CONTAINER = '107';
microstrategy.SUBOBJTYPE_CONTAINER_TITLEBAR = 'ctitl';
microstrategy.SUBOBJTYPE_DOC_TEXT = '106';
microstrategy.SUBOBJTYPE_DOC_IMAGE = '102';
microstrategy.SUBOBJTYPE_DOC_LINE = '105';
microstrategy.SUBOBJTYPE_DOC_SHAPE = '101';
microstrategy.SUBOBJTYPE_DOC_SHAPE_ROUND = '112';
microstrategy.SUBOBJTYPE_DOC_TEMPLATE = '52';
microstrategy.SUBOBJTYPE_DOC_REPORT_TEMPLATE = microstrategy.SUBOBJTYPE_DOC_TEMPLATE + "|" + "R";
microstrategy.SUBOBJTYPE_DOC_GRID_TEMPLATE = microstrategy.SUBOBJTYPE_DOC_TEMPLATE + "|" + microstrategy.GRID_EFFECTIVE_VIEW_GRID;
microstrategy.SUBOBJTYPE_DOC_GRAPH_TEMPLATE = microstrategy.SUBOBJTYPE_DOC_TEMPLATE + "|" + microstrategy.GRID_EFFECTIVE_VIEW_GRAPH;
microstrategy.SUBOBJTYPE_DOC_GRID_GRAPH_TEMPLATE = microstrategy.SUBOBJTYPE_DOC_TEMPLATE + "|" + microstrategy.GRID_EFFECTIVE_VIEW_GRID_GRAPH;
microstrategy.GRAPH_CTL = '52G'; //Special case for graph control type
microstrategy.SUBOBJTYPE_DOC_PANEL_STACK = "8";
microstrategy.SUBOBJTYPE_DOC_PANEL = "9";
microstrategy.SUBOBJTYPE_DOC_SELECTOR_CONTROL = "111";
microstrategy.SUBOBJTYPE_DOC_WIDGET = "113";
microstrategy.SUBOBJTYPE_SEL_HANDLE = 'shan';
microstrategy.SUBOBJTYPE_FOLDER_LIST = 'folderList';
microstrategy.SUBOBJTYPE_FOLDER_UP = 'folderUp';
microstrategy.SUBOBJTYPE_FILE_SEARCH = 'fileSearch';
microstrategy.SUBOBJTYPE_FILE_LIST = 'fileList';
microstrategy.SUBOBJTYPE_BTN = 'btn';
microstrategy.SUBOBJTYPE_BTN_HANDLE = 'btnh';
microstrategy.SUBOBJTYPE_VRULER = 'vRul';
microstrategy.SUBOBJTYPE_VRULER_SHADE = 'vRulS';
microstrategy.SUBOBJTYPE_HRULER = 'hRul';
microstrategy.SUBOBJTYPE_HRULER_SHADE = 'hRulS';
microstrategy.SUBOBJTYPE_TAB_CONTAINER = 'tabCont';
microstrategy.SUBOBJTYPE_TAB_SAMPLE = "sample";
microstrategy.SUBOBJTYPE_TAB_SECTION = "tabSection";
microstrategy.SUBOBJTYPE_FORMULA_BAR_AREA = "fmlaArea";
microstrategy.SUBOBJTYPE_FORMULA_BAR_TEXT_AREA = "fmlaTextArea";
microstrategy.SUBOBJTYPE_RESIZE_VLINE = "vline";
microstrategy.SUBOBJTYPE_RESIZE_HLINE = "hline";
microstrategy.SUBOBJTYPE_ATTRIBUTE = 'ATT';
microstrategy.SUBOBJTYPE_ATTRIBUTE_FORM = 'ATTFORM';
microstrategy.SUBOBJTYPE_METRIC = 'MV';
microstrategy.SUBOBJTYPE_IMG = 'cimg';
microstrategy.SUBOBJTYPE_PREVIEW_PANE = 'prv';
microstrategy.SUBOBJTYPE_OUTLINE_MODE_IMG = 'outimg';
microstrategy.SUBOBJTYPE_PANEL_CONTAINER = "pc";
microstrategy.SUBOBJTYPE_WINDOW_BUTTON = "wBtn";
microstrategy.SUBOBJTYPE_SLIDER = "slider";
microstrategy.DSSTYPE_TEMPLATE = "2";
microstrategy.DSSTYPE_RPT_DEFINITION = "3";
microstrategy.DSSTYPE_DOC_DEFINITION = "55";
microstrategy.DSSTYPE_FOLDER = "8";
microstrategy.DSSTYPE_CONSOLIDATION_ELEMENT = "48";
microstrategy.DSSTYPE_METRIC = "4";
microstrategy.DSSTYPE_USER_METRIC = "100";
microstrategy.DSSTYPE_USER_SUMMARY_METRIC = "101";
microstrategy.DSSTYPE_ATTRIBUTE = "12";
microstrategy.DSSTYPE_ATTRIBUTE_FORM = "21";
microstrategy.DSSTYPE_FILTER = "1";
microstrategy.DSSTYPE_PROMPT = "10";
microstrategy.DSSTYPE_CONSOLIDATION = "47";
microstrategy.DSSTYPE_CUSTOM_GROUP = "257";
microstrategy.DSSTYPE_DIMENSION = "14";
microstrategy.DSSTYPE_GRID = "768";
microstrategy.DSSTYPE_GRAPH = "769";
microstrategy.DSSTYPE_GRID_AND_GRAPH = "774";
microstrategy.DSSTYPE_REPORT_CUBE = "776";
microstrategy.DSSTYPE_HIERARCHY = "14";

microstrategy.DISPUNITTYPE_ELEMENT = "1048576";

microstrategy.DSSSUB_TYPE_FILTER = "256";
microstrategy.DSSSUB_TYPE_RW = "14081";

microstrategy.DSSSUB_TYPE_PROMPT = 0x0a00;
microstrategy.DSSSUB_TYPE_PROMPT_BOOLEAN = 0x0a01;
microstrategy.DSSSUB_TYPE_PROMPT_LONG = 0x0a02;
microstrategy.DSSSUB_TYPE_PROMPT_STRING = 0x0a03;
microstrategy.DSSSUB_TYPE_PROMPT_DOUBLE = 0x0a04;
microstrategy.DSSSUB_TYPE_PROMPT_DATE = 0x0a05;
microstrategy.DSSSUB_TYPE_PROMPT_BIG_DECIMAL = 0x0a0b;
microstrategy.DSSSUB_TYPE_PROMPT_OBJECTS = 0x0a06;
microstrategy.DSSSUB_TYPE_PROMPT_ELEMENTS = 0x0a07;
microstrategy.DSSSUB_TYPE_PROMPT_EXPRESSION = 0x0a08;
//microstrategy.DSSSUB_TYPE_PROMPT_ExpressionDraft = 0x0a09;
microstrategy.DSSSUB_TYPE_PROMPT_DIMPTY = 0x0a0a;


microstrategy.HTMLATTR_SCRIPTCLASS = 'scriptclass';
microstrategy.HTMLATTR_ID = 'id';
microstrategy.HTMLATTR_OBJTYPE = 'ty';
microstrategy.HTMLATTR_DSSTYPE = 'dss_ty';
microstrategy.HTMLATTR_DISPLAY_NAME = 'ds';
microstrategy.HTMLATTR_SUBOBJTYPE = 'sty';
microstrategy.HTMLATTR_STYLE = 'styst';
microstrategy.HTMLATTR_OBJINDEX = 'ind';
microstrategy.HTMLATTR_DISPUNITTYPE = 'dty';
microstrategy.HTMLATTR_DISPLAY_NAME = 'ds';
microstrategy.HTMLATTR_ORIENTATION = 'or';
microstrategy.HTMLATTR_ORIENTATIONS_SUPPORTED = 'ors';
microstrategy.HTMLATTR_GRIDCELL_AXIS = 'ax';
microstrategy.HTMLATTR_GRIDCELL_DEPTH = 'dpt';
microstrategy.HTMLATTR_GRIDCELL_ID = "i";
microstrategy.HTMLATTR_GRIDCELL_ORDINAL = 'o';
microstrategy.HTMLATTR_GRIDROW_ORDINAL = 'o';
microstrategy.HTMLATTR_GRIDROW_MAX_DEPTH = 'mx';
microstrategy.HTMLATTR_GRIDROW_LEVEL = 'level';
microstrategy.HTMLATTR_GRIDCELL_ATTR_COL_TITLE_MISSING = 'ctm';
microstrategy.HTMLATTR_CMD_ID = 'cmdid';
microstrategy.HTMLATTR_CMD_TYPE = 'cmdtp';
microstrategy.HTMLATTR_CMD_VALUE = 'cmdvl';
microstrategy.HTMLATTR_CMD_FORMAT_TYPE = 'cmdft';
microstrategy.HTMLATTR_CMD_PICKER = 'cmdpk';
microstrategy.HTMLATTR_CMD_PROP = 'cmdprop';
microstrategy.HTMLATTR_CMD_LEVEL = "cmdlvl";
microstrategy.HTMLATTR_DYN_TITLE = "dynTT";
microstrategy.HTMLATTR_COLOR = 'color';
microstrategy.HTMLATTR_FILTER_VALUE = 'ftv';
microstrategy.HTMLATTR_FILTER_TYPE = 'ftt';
microstrategy.HTMLATTR_FILTER_COMPARISON = 'ftc';
microstrategy.HTMLATTR_FILTER_COMPARISON_DEFAULT = '0';
microstrategy.HTMLATTR_FILTER_COMPARISON_BINARY = '1';
microstrategy.HTMLATTR_DSS_ID = 'oid';
microstrategy.HTMLATTR_DSS_FORMULA = 'frma';
microstrategy.HTMLATTR_DSS_TYPE = 'oty';
microstrategy.HTMLATTR_DERIVED_METRIC = 'dr';
microstrategy.HTMLATTR_DSS_SUBTYPE = 'ost';
microstrategy.HTMLATTR_DSS_SET = 'ods';
microstrategy.HTMLATTR_DSS_DESCRIPTION = "otd";
microstrategy.HTMLATTR_POINTS_TO = 'pt';
microstrategy.HTMLATTR_TARGET = "tg";
microstrategy.HTMLATTR_DND_SOURCE = "dg";
microstrategy.HTMLATTR_DO_COND_FORMAT = "cf";
microstrategy.HTMLATTR_HEIGHT_MODE = 'hm';
microstrategy.HTMLATTR_HEIGHT = 'ht';
microstrategy.HTMLATTR_WIDTH_MODE = 'wm';
microstrategy.HTMLATTR_WIDTH = 'wd';
microstrategy.HTMLATTR_VISIBLE = 'visible';
microstrategy.HTMLATTR_OLD_HEIGHT = 'oldht';
microstrategy.HTMLATTR_OLD_WIDTH = 'oldwd';
microstrategy.HTMLATTR_OLD_TOP = 'oldtop';
microstrategy.HTMLATTR_OLD_LEFT = 'oldleft';
microstrategy.HTMLATTR_HAS_CONDITIONAL_FORMATTING = 'hcf';
microstrategy.HTMLATTR_VISIBLE_HTML_VIEW_MODE = 'shvm';
microstrategy.HTMLATTR_CAN_GROW = 'cg';
microstrategy.HTMLATTR_CAN_SHRINK = 'cs';
microstrategy.HTMLATTR_MAX_HEIGHT = 'mh';
microstrategy.HTMLATTR_CAN_GROW_HORIZONTAL = 'cgh';
microstrategy.HTMLATTR_CAN_SHRINK_HORIZONTAL = 'csh';
microstrategy.HTMLATTR_MAX_WIDTH = 'mw';
microstrategy.HTMLATTR_IS_HORIZONTAL = 'hz';
microstrategy.HTMLATTR_IS_BEGIN_HORIZONTAL = 'bhz';
microstrategy.HTMLATTR_IS_END_HORIZONTAL = 'ehz';
microstrategy.HTMLATTR_HIDE_IF_EMPTY = 'he';
microstrategy.HTMLATTR_REPEAT_SECTION = 'rpts';
microstrategy.HTMLATTR_FIT_EXCEL_ROW_HEIGHT = 'ferh';
microstrategy.HTMLATTR_KEEP_SECTION_TOGETHER = 'kst';
microstrategy.HTMLATTR_REPEAT_HORIZONTALLY = 'rpth';
microstrategy.HTMLATTR_FORCE_NEW_PAGE = 'fnp';
microstrategy.HTMLATTR_AUTO_RESIZE_IN_DESIGNMODE = 'ard';
microstrategy.HTMLATTR_HTML_TYPE = 'htype';
microstrategy.HTMLATTR_HTML_SOURCE = 'hsrc';
microstrategy.HTMLATTR_HTML_TEXT = 'htxt';
microstrategy.HTMLATTR_IS_LINK = 'isl';
microstrategy.HTMLATTR_ROUNDED_CORNERS = 'rc';
microstrategy.HTMLATTR_DROP_SHADOW = 'dsw';
microstrategy.HTMLATTR_DROP_SHADOW_EFFECT = 'dse';
microstrategy.HTMLATTR_RADIUS = 'rd';
microstrategy.HTMLATTR_TOP_CORNERS_ONLY = 'tco';
microstrategy.HTMLATTR_BOTTOMLEFT_CORNER_RADIUS = 'blcr';
microstrategy.HTMLATTR_TOPLEFT_CORNER_RADIUS = 'tlcr';
microstrategy.HTMLATTR_ALPHA = 'alpo';
microstrategy.HTMLATTR_ALPHA_EFFECT = 'alpe';
microstrategy.HTMLATTR_LOCK_ASPECT_RATIO = "lar";
microstrategy.HTMLATTR_NEW_WINDOW = 'nw';
microstrategy.HTMLATTR_IMAGE_SOURCE = 'imgsrc';
microstrategy.HTMLATTR_LINK_HREF = 'href';
microstrategy.HTMLATTR_LINK_HREFVALUE = 'hv';
microstrategy.HTMLATTR_APPLIES_TO = 'at';
microstrategy.HTMLATTR_GRID_AREA_PCT = 'gap';
microstrategy.HTMLATTR_DISPLAY_MODE = 'dm';
microstrategy.HTMLATTR_GRID_POS = 'gpos';
microstrategy.HTMLATTR_RESIZE = 'rsz';
microstrategy.HTMLATTR_PRIMEDATAID = 'pDataId';
microstrategy.HTMLATTR_DETAILS_SECTION = 'dt';
microstrategy.HTMLATTR_NUMBER_FORMAT_DECIMAL_PLACES = 'ndp';
microstrategy.HTMLATTR_NUMBER_FORMAT_CATEGORY = 'nct';
microstrategy.HTMLATTR_NUMBER_FORMAT_NEGATIVE_NUMBERS = 'nnn';
microstrategy.HTMLATTR_NUMBER_FORMAT_CURRENCY_SYMBOL = 'ncs';
microstrategy.HTMLATTR_NUMBER_FORMAT_CURRENCY_POSITION = 'ncp';
microstrategy.HTMLATTR_NUMBER_FORMAT_THOUSAND_SEPARATOR = 'nth';
microstrategy.HTMLATTR_NUMBER_FORMAT_STRING = 'nfs';
microstrategy.HTMLATTR_FORM_POS = 'FRMPOS';
microstrategy.HTMLATTR_FORM_ID = 'FRMID';
microstrategy.HTMLATTR_FORM_NAME = 'FRMNAME';
microstrategy.HTMLATTR_FORM_LIST = 'FRMLIST';
microstrategy.HTMLATTR_SECTION_ID = 'sct';
microstrategy.HTMLATTR_DTOP = 'dtp';
microstrategy.HTMLATTR_DWIDTH = 'dwh';
microstrategy.HTMLATTR_DHEIGHT = 'dht';
microstrategy.HTMLATTR_DLEFT = 'dlf';
microstrategy.HTMLATTR_ATTRIBUTE_ID = 'atid';
microstrategy.HTMLATTR_PARENT_ID = 'pid';
microstrategy.HTMLATTR_DESCRIPTION = "ds";
microstrategy.HTMLATTR_NAME = "nm";
microstrategy.HTMLATTR_ACL = "acl";
microstrategy.HTMLATTR_BORDER = 'br'; //indicates if the object has a border or not
microstrategy.HTMLATTR_PAGE_BREAK = "pbs";
microstrategy.HTMLATTR_SHOW_REPEAT_SECTION = "rps";
microstrategy.HTMLATTR_IS_LOCKED = "ilk";
microstrategy.HTMLATTR_TOOLTIP_FORMULA = "tt";
microstrategy.HTMLATTR_SHOW_WINDOW_TITLE = 'swt'; //indicates if we are showing the title bar of the portal window
microstrategy.HTMLATTR_WIDGET_SHOW_WINDOW_TITLE = 'swwt';//indicates if we are showing the title bar of the portal window on widget mode
microstrategy.HTMLATTR_WINDOW_STATE = 'ws'; //indicates the state of the portal window around an object
microstrategy.HTMLATTR_WINDOW_LAST_STATE = 'wls';
microstrategy.HTMLATTR_WINDOW_TITLE = 'wt'; //indicates
microstrategy.HTMLATTR_TITLE_BAR_DISPLAY = 'tbd';
microstrategy.HTMLATTR_SECTION_NAME = 'sn'; //indicates the section name (e.g. itemList section in the selector HTML).
microstrategy.HTMLATTR_QUICK_SWITCH = 'qs';
microstrategy.HTMLATTR_USE_AS_INFORMATION_WINDOW = 'uaiw';
microstrategy.HTMLATTR_HORIZONTAL_SWIPE_CHANGE = 'ehstc';

microstrategy.HTMLATTR_BORDER_3D_STYLE = "b3dstyle";
microstrategy.HTMLATTR_BORDER_3D_WEIGHT = "b3dweight";
microstrategy.HTMLATTR_BORDER_3D_TOP_COLOR = "b3dtc";
microstrategy.HTMLATTR_BORDER_3D_LEFT_COLOR = "b3dlc";
microstrategy.HTMLATTR_BORDER_3D_RIGHT_COLOR = "b3drc";
microstrategy.HTMLATTR_BORDER_3D_LEFT_COLOR = "b3dlc";
microstrategy.HTMLATTR_BORDER_TOP_COLOR = "btc";
microstrategy.HTMLATTR_BORDER_LEFT_COLOR = "blc";
microstrategy.HTMLATTR_BORDER_RIGHT_COLOR = "brc";
microstrategy.HTMLATTR_BORDER_BOTTOM_COLOR = "bbc";
microstrategy.HTMLATTR_BORDER_TOP_STYLE = "bts";
microstrategy.HTMLATTR_BORDER_LEFT_STYLE = "bls";
microstrategy.HTMLATTR_BORDER_RIGHT_STYLE = "brs";
microstrategy.HTMLATTR_BORDER_BOTTOM_STYLE = "bbs";
microstrategy.HTMLATTR_LINE_COLOR = "lc";
microstrategy.HTMLATTR_LINE_STYLE = "ls";
microstrategy.HTMLATTR_LINE_WEIGHT = "lw";
microstrategy.HTMLATTR_GRID_CELL_TYPE = "cty";
microstrategy.HTMLATTR_GRID_UNIT_POS = "UPT"; //the template unit that a cell belongs to: axis, pos
microstrategy.HTMLATTR_IS_DATASET_JOIN_PRIMARY = 'ijp'; //indicates if the dataset is a primary join dataset
microstrategy.HTMLATTR_GRID_OVERFLOW = "ovf";
microstrategy.HTMLATTR_TEXT_OVERFLOW = "tovf";
microstrategy.HTMLATTR_GRID_EXPORT_OVERFLOW = "xovf";
microstrategy.HTMLATTR_GRAPH_EXPORT_OVERFLOW = "xgovf";

microstrategy.HTMLATTR_WIDGET_CLASS = "twc";
microstrategy.HTMLATTR_WIDGET_RSL_PATH = "rsl";
microstrategy.HTMLATTR_WIDGET_IS_APP = "iap";
microstrategy.HTMLATTR_NON_FLASH_RENDER = "nfr";
microstrategy.HTMLATTR_PDF_RENDER = "pr";
microstrategy.HTMLATTR_EXCEL_RENDER = "er";
microstrategy.HTMLATTR_DHTML_RENDER = "dr";
microstrategy.HTMLATTR_SEC_DATA_PROVIDERS = "sdp";
microstrategy.HTMLATTR_TRANSITION = "ttr";
microstrategy.HTMLATTR_TRANS_DURATION = "tdr";
microstrategy.HTMLATTR_LOCKED = "lck";
microstrategy.HTMLATTR_IS_VIS_GRID_BONE = 'ivgb'; // Issue 285545: node to identify the div that contains the grid bone on an AJAX visualization
microstrategy.HTMLATTR_SELECTOR_SELECTION_COLOR = 'ssc';
microstrategy.HTMLATTR_SELECTOR_SELECTION_STYLE = 'sstyle';

microstrategy.HTMLATTR_IPHONE_VIS = "iphv";
microstrategy.HTMLATTR_IPAD_VIS = "ipadv";
microstrategy.HTMLATTR_WIDGET_PROPS = 'wp';

microstrategy.GRIDCELLTYPE_UNIT_HEADER = "1";
microstrategy.GRIDCELLTYPE_UNIT_VALUE = '2';
microstrategy.GRIDCELLTYPE_SUBTOTAL_HEADER = "3";
microstrategy.GRIDCELLTYPE_SUBTOTAL_VALUE = "4";
microstrategy.GRIDCELLTYPE_LEVEL_ALL = "5";

microstrategy.GRIDCELLTYPE_LEVEL_NONE = '0';
microstrategy.GRIDCELLTYPE_LEVEL_MULTIPLE = '-1';
microstrategy.GRID_TARGET_NONE = '0';
microstrategy.GRID_TARGET_MULTIPLE= '-1';

microstrategy.FORMAT_LEVEL_FLAG_VIEWER = 0;
microstrategy.FORMAT_LEVEL_FLAG_DOC = 1;
microstrategy.FORMAT_LEVEL_FLAG_DOC_SELECTIONS = 2;

microstrategy.GRIDCELLTYPE_METRIC_DATA = "data";

microstrategy.TRUE = "-1";
microstrategy.FALSE = "0";

microstrategy.ACL_EXECUTE = 128;
microstrategy.ACL_USE = 64;

microstrategy.COPY_ITEM_SEPERATOR = ";";

microstrategy.OBJ_PREFIX = 'W';

microstrategy.VISIBLE_ELEMS_NAME = "visElem";
microstrategy.VISIBLE_ELEMS_RULERS = 1;
microstrategy.VISIBLE_ELEMS_GRID = 2;
microstrategy.VISIBLE_ELEMS_DIVIDER = 4;

microstrategy.OK_BUTTON = 1;
microstrategy.CANCEL_BUTTON = 2;
microstrategy.APPLY_BUTTON = 4;

microstrategy.DESIGN_MODE = 1;
microstrategy.VIEW_MODE = 2;

microstrategy.RW_VIEW_MODE_STATIC = 1;
microstrategy.RW_VIEW_MODE_INTERACTIVE = 2;
microstrategy.RW_VIEW_MODE_EDITABLE = 4;
microstrategy.RW_VIEW_MODE_FLASH = 8;

microstrategy.IN_OUTLINE_MODE = false;
microstrategy.IS_RELOAD = false;

microstrategy.ALLOW_EDIT_MODE = 1;
microstrategy.NOT_ALLOW_EDIT_MODE = 2;

microstrategy.HTML_CONTAINER_TYPE_IFRAME = "0";
microstrategy.HTML_CONTAINER_TYPE_HTML = "1";

microstrategy.WINDOW_TITLE_HEIGHT = "20";
microstrategy.WINDOW_STATE_NORMAL= "0";
microstrategy.WINDOW_STATE_MINIMIZED = "1";
microstrategy.WINDOW_STATE_MAXIMIXED= "2";

microstrategy.MARQUEE_STYLE = microstrategy.MARQUEE_STYLE_PARTIAL;
microstrategy.MARQUEE_STYLE_PARTIAL = 0;
microstrategy.MARQUEE_STYLE_FULL = 1;

microstrategy.DPI_CONVERSION = 96;
microstrategy.BASE_DPI = 96;
microstrategy.ZOOM_FACTOR = 100;
microstrategy.ZOOM_STATIC = '0';
microstrategy.ZOOM_FIT_WIDTH = '1';
microstrategy.ZOOM_FIT_PAGE = '2';
microstrategy.GRID_IMAGE = "grid96MediumInch.gif";
microstrategy.SNAP_SIZE = 12;
microstrategy.CURSOR_OFFSET = 5;
microstrategy.DND_HILITE_WIDTH = 3;

microstrategy.SNAP_OFF = false;
microstrategy.SNAP_DIRET_POS = 1;
microstrategy.SNAP_DIRET_NEG = -1;

microstrategy.DISPLAY_MODE_GRID = 1;
microstrategy.DISPLAY_MODE_GRAPH = 2;
microstrategy.DISPLAY_MODE_GRID_AND_GRAPH = 3;
microstrategy.FIRST_VISUALIZATION_VIEW_MODE = 50;

microstrategy.RWD_EXECUTION_MODE_DATA = 1;

microstrategy.REPORT_EXECUTION = 1;
microstrategy.RWD_EXECUTION = 2;

microstrategy.FORM_LIST_NAME = 0;
microstrategy.FORM_LIST_ID = 1;
microstrategy.FORM_LIST_STATUS = 2;

microstrategy.FORM_ON_VIEW = 1;
microstrategy.FORM_ON_WS = 2;
microstrategy.FORM_NOT_ON_WS = 3;

microstrategy.DESIGNMODE_NOBORDER_STYLE = "#999999 1px dashed"; //if an image/text has no border in design mode, it gets this gray dashed border
microstrategy.HAS_BORDER = 1;
microstrategy.NO_BORDER = 0;

microstrategy.RESIZE_VERTICAL = 1;
microstrategy.RESIZE_HORIZONTAL = 2;

microstrategy.WIDTH_UPDATE = 1;
microstrategy.HEIGHT_UPDATE = 2;
microstrategy.WIDTH_AND_HEIGHT_UPDATE = 3;

microstrategy.FIX_MODE = 0;
microstrategy.HUNDRED_PERCENT_MODE = 1;
microstrategy.AUTO_MODE = 2;
microstrategy.IS_RWD_DIRTY = microstrategy.FALSE;
microstrategy.IS_OFFICE_EXPORT = microstrategy.FALSE;

microstrategy.OPEN_EDITOR_ACTION_ADD = 1;
microstrategy.OPEN_EDITOR_ACTION_EDIT = 0;

microstrategy.PAGE_FULL_SCREEN_MODE = 2;
microstrategy.PAGE_NORMAL_SCREEN_MODE = 1;

microstrategy.FORMATTING_PROP_THRESHOLD = "t";
microstrategy.FORMATTING_PROP_TOC_FONT = "df";
microstrategy.FORMATTING_PROP_DERIVED_ELEMENT = "de";

microstrategy.TAB_SWITCH_MODE = 'switchMode';
microstrategy.TAB_SWITCH_MODE_CACHED = 0;
microstrategy.TAB_SWITCH_MODE_FETCH = 1;

//properties
microstrategy.bones = {};
microstrategy.zones = new Array;
microstrategy.observerItems = null;
microstrategy.updateManager = null;
microstrategy.number = null;
microstrategy.descriptors = null;
microstrategy.styleObj = null;
microstrategy.controlVariables = {};
microstrategy.formatObj = null;
microstrategy.mstrwid = '';
microstrategy.bonesToRegister = [];
microstrategy.zoomType = microstrategy.ZOOM_TYPE_STATIC;
microstrategy.viewerBoneId = '';
microstrategy.displayLocaleID = null;

microstrategy.prototype.DISPLAY_MODE = microstrategy.DESIGN_MODE;
microstrategy.prototype.EDIT_MODE = microstrategy.ALLOW_EDIT_MODE;
//microstrategy.prototype.EXECUTION_SCOPE = microstrategy.REPORT_EXECUTION;
microstrategy.prototype.activeCXMenu = null;
microstrategy.prototype.activeCXBone = null;
microstrategy.prototype.RMCTarget = null;
microstrategy.prototype.isCXMenuOpen = false;
//If the JUILS context menu is open
microstrategy.prototype.isJLSCXMenuOpen = false;
microstrategy.primeDataSetId = null;
microstrategy.sortDefinedOnDefault = false;
microstrategy.waitPageDelay = "0";
microstrategy.showWaitPopup = true;

//microstrategy.prototype.RESIZE_SUBSECTIONS = microstrategy.RESIZE_EACH_SUBSECTION;
microstrategy.IGNORE_RESIZE = 1;
microstrategy.RESIZE_TO_FIRST_SUBSECTION = 2;
microstrategy.RESIZE_EACH_SUBSECTION = 3;

microstrategy.REPORT_FMT_TOOLBAR = ""; //report format toolbar id

microstrategy.FORMAT_TYPE_MAIN = '1';
microstrategy.formatType = microstrategy.FORMAT_TYPE_MAIN;
//microstrategy.formatType = 2;

microstrategy.RESTORE_LEFT = 0;
microstrategy.RESTORE_TOP = 1;
microstrategy.RESTORE_BOTH = 2;

microstrategy.ACCORDION_REPORT_RP_OBJECT_PANEL = 'workingSet';
microstrategy.ACCORDION_REPORT_ALL_OBJECT_PANEL = 'objectBrowser';
microstrategy.ACCORDION_REPORT_RELATED_RP_PANEL = 'relatedReports';
microstrategy.ACCORDION_REPORT_NOTES_PANEL = 'notes';

microstrategy.ACCORDION_RW_DATASET_PANEL = 'workingSet';
microstrategy.ACCORDION_RW_RELATED_RP_PANEL = 'relatedReports';
microstrategy.ACCORDION_RW_NOTES_PANEL = 'notes';
microstrategy.ACCORDION_RW_OUTLINE_PANEL = 'outlineView';

microstrategy.DHTML_RENDERER_SAME_AS_WIDGET = '1';
microstrategy.DHTML_RENDERER_SAME_AS_PDF_AND_EXCEL = '0';

microstrategy.GRID_UNIT_CONTAINER = 0;
microstrategy.GRID_BORDERS = 1;
microstrategy.GRID_OTHER = 2;
microstrategy.HTML_TEXT_NODE_TYPE = 3;

microstrategy.gridFormatCache = {};
microstrategy.graphPropertyCache = {};
microstrategy.WEB_API_ERROR_CODES = {
			MSI_SERVER_NAME_NOT_INITIALIZED:0x800438F3,  //Server Name Not initialized
			MSI_INVALID_SESSION_ID:0x800438F4,  //Session ID invalid
			E_MSI_USERMGR_USER_NOTFOUND:0x800430A5,  // UserLogin expired
			E_MSI_CONNECT_FAILED:0x80043705
};
document.onmousedown = new Function("e", "return microstrategy.onMouseDownHandler(e)");

microstrategy.EXEC_MODE_EXCEL = '4';
microstrategy.EXEC_MODE_PDF = '3';
microstrategy.EXEC_MODE_FLASH = '7';

microstrategy.FILTER_BOX_NAME = "drillFilterElementList";
microstrategy.DRILL_BOX_NAME = "deDrillElementList";

microstrategy.VIS_EDITOR_SCOPE_REPORT = 1;
microstrategy.VIS_EDITOR_SCOPE_RW_GRID = 2;
microstrategy.VIS_EDITOR_SCOPE_RW = 4;
microstrategy.VIS_EDITOR_SCOPE_RW_LAYOUT = 8;

microstrategy.ENCODED_AMPERSAND = "%26",
microstrategy.ENCODED_EQUALS = "%3D",


/**
 * Global event handler to process the mouse down event. It triggers an 'ondocumentclick' event for the bones.
 * @memberOf microstrategy
 * @param {HTMLEvent} e The event object (W3C complaint browsers only).
 * @returns {Boolean} true if no exception during the process or null if there is an exception.  
 */
microstrategy.onMouseDownHandler = function(e) {
    //@class=microstrategy;@method=onMouseDownHandler;
    //Purpose: trigger an ondocumentclick event for the bones
    try {
        if (microstrategy.eventManager) {
            microstrategy.eventManager.notifyOrphanBones('ondocumentclick', e);
        }
        microstrategy.hidePopups();
        return true;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Responsible for closing all pop up menus and inputs.
 */   
microstrategy.hidePopups = function(force) {
    if (typeof(hidePopupMenus) != 'undefined') hidePopupMenus(force);
    if (typeof(hideIncFetchGoToDialog) != 'undefined') hideIncFetchGoToDialog();
}

/**
 * Resets cached active context menu properties.
 * @memberOf microstrategy
 * @param {Object} oTarget The new active menu properties.
 * @param {HTMLEvent} e The event object (W3C complaint browsers only).
 * @refactoring Used only in one place (Menu.js). Refactor to an inline method.
 */
microstrategy.updateActiveCXProps = function(oTarget, e) {
    //@class=microstrategy;@method=resetCXProperties;
    //Purpose: resets cached active context menu properties. 
    microstrategy.activeCXMenu = oTarget;
    microstrategy.RMCTarget = getEventTarget(e);
    microstrategy.activeCXBone = null;     // we will update and cache the information when bone is first required.
}

/**
 * Sets the context menu status to be true of false.
 * @memberOf microstrategy
 * @param {Boolean} isOpen Sets the value to be true if the context menu is open, otherwise sets the value to be false.
 * @refactoring Used only in two place in one file (Menu.js). Refactor to a local method.
 */
microstrategy.setContextMenuStatus = function(isOpen) {
    microstrategy.isCXMenuOpen = isOpen;
}


/**
 * TQMS:358415
 * Sets the JUILS context menu status to be true of false.
 * @memberOf microstrategy
 * @param {Boolean} isOpen Sets the value to be true if the context menu is open, otherwise sets the value to be false.
 */
microstrategy.setJLSCXMenuOpen = function (isOpen){
    microstrategy.isJLSCXMenuOpen = isOpen;
}

/**
 * Gets the context menu open status.
 * @memberOf microstrategy
 * @returns {Boolean} true if the context menu is opening or false when it is closed. 
 * @refactoring Used only in one place (mstrStaticDoc.js). Refactor to an inline method.
 */
microstrategy.isContextMenuOpen = function() {
    return microstrategy.isCXMenuOpen || microstrategy.isJLSCXMenuOpen;
}

/**
 * Gets the bone associated with the active context menu.
 * @memberOf microstrategy
 * @returns {mstrBoneImpl} The active context menu bone object or null if there is an exception.
 */
microstrategy.getActiveCXBone = function() {
    //@class=microstrategy;@method=getActiveCXBone;
    //Purpose: closes bone around the active context menu. Caches the information 
    try {
        if (!microstrategy.activeCXBone) {
            microstrategy.activeCXBone = microstrategy.findBone(microstrategy.activeCXMenu);
        }
        return microstrategy.activeCXBone;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Updates the first level properties of a registered bone, if the bone does not exist, it will register it.
 * @memberOf microstrategy
 * @param {Object} propsObj object used to update the properties in the bone object.
 */
microstrategy.updateBone = function(propsObj) {
    //@class=microstrategy;@method=updateBone;
    //Purpose: Updates the first level properties of a registered bone, if the bone does not exist, it will register it.
    try {
        if (microstrategy.bone(propsObj.id)) {
            microstrategy.bone(propsObj.id).absorbObject(propsObj.properties);
        } else {
            microstrategy.bonesToRegister.push({id:propsObj.id, loadCondition:propsObj.loadCondition, properties:propsObj.properties});
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
    return null;
}
/**
 * Creates and Stores a bone for a given HTML element.
 * @memberOf microstrategy
 * @param {String} id The id of the HTML element.
 * @param {String} loadCondition The loading condition evaluated before registering the bone.
 * @param {Object} propsObj The property object used to update the properties in the newly created bone object.
 */
microstrategy.registerBone = function(id, loadCondition, propsObj) {
    //@class=microstrategy;@method=registerBone;
    //Purpose: Create & store a bone for a given HTML element.
    try {
        var elem = getElementById(id);
        if (!elem) return null;
        
        // Initialize control variable to false to indicate that this bone hasn't been instantiated yet.
        microstrategy.controlVariables[id] = false;
        
        // Extract the script class and make sure the javascript file is loaded (by checking for the presence of 
        // the constructor in the window scope).
        var scriptClass = elem.getAttribute(microstrategy.HTMLATTR_SCRIPTCLASS);

        var conditionStatus = false;
        
        try {
            conditionStatus = checkJSExists(scriptClass) && eval(loadCondition);
        } catch(e) {
            conditionStatus = false;
        }
        
        if (conditionStatus) {
            var bone = this.callConstructor([id], scriptClass);
            if (bone) {
                this.bones[bone.id] = bone;
                microstrategy.controlVariables[id] = true;
                
                // If this bone is the viewerBone then cache it's id for use in getViewerBone.
                if (bone.viewerBone) {
                    this.viewerBoneId = id;
                }
                
                if (propsObj) {
                    // If the propsObj is a string than it's a bug.  However, we will try to use it anyway.
                    if (typeof(propsObj) == 'string') {
                        microstrategy.errors.log("Unexpected properties object type at microstrategy.registerBone.");
                        eval("propsObj = " + propsObj)
                    }

                    // Copy properties of propsObj onto bone instance.
                    for (var p in propsObj) {
                        bone[p] = propsObj[p];
                    }
                }
                return bone;
            }
        } else {
            // Set timeout to wait for constructor to be loaded.
            window.setTimeout(function registerBoneTimeout() {
                microstrategy.registerBone(id, loadCondition, propsObj);
            }, 250);
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
    return null;
}


/**
 * Removes a stored bone.
 * @memberOf microstrategy
 * @param {String} id  The id of the bone to be removed.
 * @returns {Boolean} true if the bone is removed successfully or null if there is an exception.
 */
microstrategy.unRegisterBone = function(id) {
    //@class=microstrategy;@method=unRegisterBone;
    //Purpose: Remove a stored bone.
    try {
        if (typeof(this.bones[id]) != 'undefined') {
            this.bones[id].onunload();
            delete this.bones[id];
        }
        return true;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Calls the constructor of a bone object and returns the created bone object.
 * @memberOf microstrategy
 * @param {String[]} aArgs The argument list used to initialize the newly create bone.
 * @param {String} scriptClass The name of the script class that specifies the class to instantiate the bone.
 * @returns {mstrBoneImpl} The created bone object or null if there is an exception.
 * @refactoring Only used locally in registerBone() function. Refactor to a local method.
 */
microstrategy.callConstructor = function(aArgs, scriptClass) {
    //@class=microstrategy;@method=callConstructor;
    //Inputs: variable -- depends on the bone.  The first argument is the ID of
    //an HTML element.  All arguments of this function are
    //passed to the bone constructor.
    try {
    
        if (!scriptClass){
            elem = getElementById(aArgs[0]);
            scriptClass = elem && elem.getAttribute(microstrategy.HTMLATTR_SCRIPTCLASS);
            if(!scriptClass) return null;
        }
        
        var obj = null;
        if (aArgs){
            obj = new window[scriptClass](aArgs[0]);
            if  (aArgs.length > 1){
                window[scriptClass].apply(obj, aArgs);
            }
        } else {
            obj = new window[scriptClass]();
        }
        
        return obj;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Gets the bone object by bone id.
 * @memberOf microstrategy
 * @id {String} id The id of the bone.
 * @returns {mstrBoneImpl} The bone object or null if the bone cannot be found.
 */
microstrategy.bone = function(id) {
    //@class=microstrategy;@method=bone;
    try {
        return (typeof(this.bones[id]) != 'undefined') ? this.bones[id] : null;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Gets the viewer bone object.
 * @memberOf microstrategy
 * @returns {mstrBoneImpl} The bone object or null if the bone cannot be found.
 */
microstrategy.getViewerBone = function() {
    //@class=microstrategy;@method=bone;
    try {
        return this.bone(this.viewerBoneId);
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
    return null;
}

/**
 * Gets the bone object by analyzing the id/sty attribute of the HTMLElement.
 * @memberOf microstrategy
 * @param {HTMLElement} elem HTMLElement
 * @returns {mstrBoneImpl} The bone object or null if the bone cannot be found.
 */
microstrategy.findBone = function(elem) {
    //@class=microstrategy;@method=findBone;
    try {
        if (elem == null) {
            return null;
        }

        var obj = findTarget(elem, microstrategy.HTMLATTR_SCRIPTCLASS);
        if (obj == null || obj.getAttribute("id") == null) {
            return null;
        }

        var bone = this.bone(obj.getAttribute("id"));
        
        if (bone) {
            return bone;
        } else if (obj.getAttribute(microstrategy.HTMLATTR_SUBOBJTYPE) == microstrategy.SUBOBJTYPE_TREE_VIEW) {
            return microstrategy.findBone(obj.parentNode);
       }

        if (elem.getAttribute(microstrategy.HTMLATTR_OBJTYPE) == microstrategy.OBJTYPE_DOC_OBJECT) {
            if (elem.getAttribute(microstrategy.HTMLATTR_SUBOBJTYPE) != microstrategy.SUBOBJTYPE_DOC_TEMPLATE) {
                return this.findBone(elem.parentNode);
            } else {
                // ~ Grids
                var tab = elem.getElementsByTagName("table");
                for (var j=0; j<tab.length; j++) {
                    var tabParent = tab[j].parentNode;
                    if (tabParent && tabParent.id.toLowerCase().indexOf("divlock") > 0) tabParent = tabParent.parentNode;
                    if (tabParent && tabParent.getAttribute(microstrategy.HTMLATTR_SCRIPTCLASS) && ( tabParent.getAttribute(microstrategy.HTMLATTR_SUBOBJTYPE) == microstrategy.SUBOBJTYPE_GRID_TABLE || tabParent.getAttribute(microstrategy.HTMLATTR_SUBOBJTYPE) == microstrategy.SUBOBJTYPE_DOC_GRID_TEMPLATE) ) {
                        var boneGrid = this.bone(tabParent.getAttribute("id"));
                        if (boneGrid && (!boneGrid.quickSwitch || boneGrid.quickSwitchCurrent)) return boneGrid;
                    }
                }
                // ~ Graphs
                var img = elem.getElementsByTagName("img");
                for (var j=0; j<img.length; j++){
                    if (img[j].parentNode && img[j].parentNode.getAttribute(microstrategy.HTMLATTR_SCRIPTCLASS)) {
                        var boneGraph = this.bone(img[j].parentNode.getAttribute("id"));
                        if (boneGraph && (!boneGraph.quickSwitch || boneGraph.quickSwitchCurrent)) return boneGraph;
                    }
                }
                // ~ Interactive View Mode Flash Viewers
                var obj = elem.getElementsByTagName("object");
                // In FF/Safari we should try to locate the embed tag instead of the object tag in IE
                if(obj == null || obj.length == 0) obj = elem.getElementsByTagName("embed");
                
                for (var j=0; j<obj.length; j++){
                    if(obj[j].parentNode && obj[j].parentNode.getAttribute(microstrategy.HTMLATTR_SCRIPTCLASS)) {
                        var boneFlash = this.bone(obj[j].parentNode.getAttribute("id"));
                        if(boneFlash && boneFlash.getGridContainerSpan) return boneFlash;
                    }
                }
                
                // ~ Failed Graphs
                var div = elem.getElementsByTagName("div");
                for (var j=0; j<div.length; j++){
                    if (div[j] && div[j].getAttribute(microstrategy.HTMLATTR_SCRIPTCLASS)) {
                        if (div[j].getAttribute(microstrategy.HTMLATTR_SUBOBJTYPE) == microstrategy.SUBOBJTYPE_DOC_GRAPH_TEMPLATE) {
                            var boneFailed = this.bone(div[j].getAttribute("id"));
                            if (boneFailed && (!boneFailed.quickSwitch || boneFailed.quickSwitchCurrent)) return boneFailed;
                        } else if (div[j].getAttribute(microstrategy.HTMLATTR_IS_VIS_GRID_BONE) == "1") {
	                        var boneVis = this.bone(div[j].getAttribute("id"));
                            if (boneVis) return boneVis;
                        }
                    }
                }
            }
        } else {
            switch (obj.getAttribute(microstrategy.HTMLATTR_OBJTYPE)) {
                case microstrategy.OBJTYPE_DOC_SUBSECTION:
                    if (obj.parentNode.getAttribute(microstrategy.HTMLATTR_SUBOBJTYPE) == microstrategy.SUBOBJTYPE_PANEL_CONTAINER) {
                        var bb = this.findBone(obj.parentNode.parentNode);
                        if ( bb != null && bb.isLoaded) {
                            return bb.getPanel(obj.getAttribute("id"));
                        } else {
                            return null;
                        }
                    }
                    // fall-through
                case microstrategy.OBJTYPE_DOC_SECTION:
                case microstrategy.OBJTYPE_DOC_HORIZONTAL_CONTAINER:
                case microstrategy.OBJTYPE_DOC:
                return (this.bone("rwb_viewer") != null) ? this.bone("rwb_viewer").getChildBone(obj) : null;
                    break;
            }
        }
        return null;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return(null);
    }

}

/**
 * Identifies the object type (the value of attribute 'ty') of an HTMLElement object.
 * @memberOf microstrategy
 * @param {HTMLElement} elem The HTMLElement. 
 * @returns {String} The object type if the element has the 'ty' attribute. Otherwise, it returns null.
 */
microstrategy.objectType = function(elem) {
    //@class=microstrategy;@method=objectType;
    try {
        var obj = this.findAncestor(elem);
        if (obj) return elem.getAttribute(microstrategy.HTMLATTR_OBJTYPE);

        return null;
    } catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Identifies the sub type (the value of attribute 'sty') of an HTMLElement object.
 * @memberOf microstrategy
 * @param {HTMLElement} elem The HTMLElement. 
 * @returns {String} The object type if the element has the 'sty' attribute. Otherwise, it returns null.
 */
microstrategy.subObjectType = function(elem) {
    //@class=microstrategy;@method=subObjectType;
    try {
        return elem && elem.getAttribute(microstrategy.HTMLATTR_SUBOBJTYPE);
    } catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Finds the first bone object which is the ancestor of give element. If the element is registered as a bone, then returns the 
 * bone object of this element. Otherwise, the function goes through the ancestors of the element and find the first 
 * bone that is registered.
 * @memberOf microstrategy
 * @param {HTMLElement} elem The HTMLElement. 
 * @returns {mstrBoneImpl} The bone object or null if a bone cannot be found.
 * @refactoring Used only one place (in docSelections.js). Refactor to an inline method.
 */
microstrategy.getRegisteredAncestor = function(elem) {
    //@class=microstrategy;@method=getRegisteredAncestor;
    if (!elem) return null;

    var src = findTarget(elem, microstrategy.HTMLATTR_SCRIPTCLASS);
    if (src) {
        var bone = microstrategy.bone(src.getAttribute("id"));
        if (bone) return bone;
        return microstrategy.getRegisteredAncestor(src.parentNode);
    }
    return null;
}

/**
 * Traces the ancestors of the given element to find a node that has 'ty' attribute.
 * @memberOf microstrategy
 * @param {HTMLElement} The HTMLElement with which to begin the search.
 * @returns {HTMLElement} The found HTMLElement or null.
 */
microstrategy.findAncestor = function(elem) {
    //@class=microstrategy;@method=findAncestor;
    if (elem) {
        return(findTarget(elem, microstrategy.HTMLATTR_OBJTYPE));
    } else {
        return null;
    }
}

/**
 * Finds the bone object the HTMLElement of which is the ancestor of the given bone.
 * @memberOf microstrategy
 * @param {mstrBoneImpl} bone The bone object to start the search with.
 * @param {String} scriptClass The value of script class
 * @returns {mstrBoneImpl} The bone object or null if not found.
 * @refactoring Replace hard coded "scriptclass" with microstrategy.HTMLATTR_SCRIPTCLASS.
 */
microstrategy.findAncestorBone = function(bone, scriptClass) {
    //@class=microstrategy;@method=findAncestorBone;
    try {
        var obj = microstrategy.findAncestorWithAtt(bone.elem, "scriptclass", scriptClass);
        if ( obj ) {
            return microstrategy.bone(obj.id);
        } else {
            return null;
        }
    } catch(err) {
        return null;
    }
}

/**
 * Finds the ancestor node with the attribute and attribute value supplied.
 * @memberOf microstrategy
 * @param {HTMLElement} oTarget The HTMLElement with which to begin the search.
 * @param {String} sFind The name of the attribute we are looking for.
 * @param {String} sValue The value of the named attribute.
 * @returns The found HTMLElement, or null.
 * @refactoring The function does the same thing as findTarget does in DHTML.js. Considering change
 * any of the function so that the functionality won't be duplicated.
 */
microstrategy.findAncestorWithAtt = function(oTarget, sAtt, sAttValue) {
    //@class=microstrategy;@method=findAncestorWithAtt;
    try {
		var fn = (sAttValue) ?
		   function (t, a, v) { return !!(t.getAttribute && t.getAttribute(a) == v) } :
		   function (t, a) { return !!(t.getAttribute && t.getAttribute(a) != null) };
		while (oTarget) {
		   if (fn(oTarget, sAtt, sAttValue)) return oTarget;
		   oTarget = oTarget.parentNode;
		}
		return null;
    }
    catch(err) {
        return null;
    }
}

/**
 * Finds the ancestor node with the given tag name.
 * @memberOf microstrategy
 * @param {HTMLElement} oTarget The HTMLElement with which to begin the search.
 * @param {String} tagName The tag name of the target element.
 * @returns {HTMLElement} The HTMLElement if found, otherwise, null.
 * @refactoring The function does the same thing as findTargetTag does in DHTM.js
 */
microstrategy.findAncestorWithTag = function(oTarget, tagName) {
    //@class=microstrategy;@method=findAncestorWithAtt;
    try {
        while (oTarget) {
            if (oTarget.tagName == tagName)
                return oTarget;
            oTarget = oTarget.parentNode;
        }
        return null;
    }
    catch(err) {
        return null;
    }
}

/**
 * Find the children nodes with given tag name, attribute and attribute value. If the start HTMLElement has the
 * tag name and attribute, it returns the element directly.
 * @memberOf microstrategy
 * @param {HTMLElement} elem The HTMLElement with which to begin the search.
 * @param {String|String[]} tagName The target tag name or a list of target tag names.
 * @param {String} sAtt The target attribute name.
 * @param {String} sAttValue The target attribute value.
 * @returns {HTMLElement|HTMLElement[]} The start HTMLElement or found HTMLElement list, or null if not found.
 */
microstrategy.findChildrenWithAtt = function(elem, tagName, sAtt, sAttValue) {
    //@class=microstrategy;@method=findChildrenWithAtt;
    try {
        if (!elem) return null;
        if (typeof(tagName) != 'object') tagName = [ tagName ];
        var result = new Array;
        var resultCount = 0;
        if(sAttValue) {
        for (var j = 0; j < tagName.length; j++) {
            if ((elem.tagName == tagName[j]) && (elem.getAttribute(sAtt) == sAttValue))
                return elem;
            var objs = elem.getElementsByTagName(tagName[j]);
            if (objs && objs.length) {
                for (var i = 0; i < objs.length; i++) {
                    if (objs[i].getAttribute(sAtt)==sAttValue)
                        result[resultCount++] = objs[i];
                }
                }
            }
        } else {
            for (var j = 0; j < tagName.length; j++) {
                 var objs = elem.getElementsByTagName(tagName[j]);
                 if (objs && objs.length) {
                    for (var i = 0; i < objs.length; i++) {
                       if (objs[i].getAttribute(sAtt) != null)
                           result[resultCount++] = objs[i];
                    }
                 }
            }
        }
                return result;
            }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Steps up through the DOM tree of the given HTMLElement to find a child node that has the given tag name 
 * and script class. Returns the bone object whose id is the same as the found element.
 * @memberOf microstrategy
 * @param {HTMLElement} elem The HTMLElement with which to begin the search.
 * @param {String} tagName The tag name of target element.
 * @param {String} scriptClass The value of the script class.
 * @returns {mstrBoneImpl} The found bone object or null. 
 * @refactoring Replace hard coded "scriptclass" with microstrategy.HTMLATTR_SCRIPTCLASS. Since the tagName 
 * should be in lower case in comparison, we need to use tagName.toLowerCase() in the condition evaluation.
 */        
microstrategy.findRegisteredChildBone = function(elem, tagName, scriptClass) {
    //@class=microstrategy;@method=findRegisteredChildBone;
    try {
        if (!elem) return null;
        if ((elem.tagName.toLowerCase() == tagName) && (isAttributePresent(elem, "scriptclass", scriptClass))) return microstrategy.bone(elem.id);

        var objs = elem.getElementsByTagName(tagName);
        for (var i = 0; objs && i < objs.length; i++) {
            if (isAttributePresent(objs[i], "scriptclass", scriptClass)) {
                return microstrategy.bone(objs[i].id);
            }
        }
        return null;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Finds the RWObject bone with given script class name.
 * @memberOf microstrategy
 * @param {HTMLElement} target The HTMLElement with which to search. 
 * @param {String} scriptClass The value of the script class. 
 * @returns {mstrBoneImpl} The found bone object or null. 
 * @refactoring Replace hard coded "scriptclass" with microstrategy.HTMLATTR_SCRIPTCLASS.
 */
microstrategy.findRWObjectBone = function(target,scriptClass) {
    //@class=microstrategy;@method=findRWObjectBone;
    try {
        if(microstrategy.objectType(target) || target.getAttribute("scriptclass")) {
            var ancestor = microstrategy.findAncestor(target);
            if(microstrategy.subObjectType(ancestor) == microstrategy.SUBOBJTYPE_DOC_PANEL_STACK) return microstrategy.findRegisteredChildBone(target, "span");
            else return microstrategy.findRegisteredChildBone(target, "div", scriptClass);
        } else return microstrategy.findBone(target);
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}


/**
 * Find the child nodes with given tag name, attribute and attribute value. If the start HTMLElement has the
 * tag name and attribute, it returns the element directly.
 * @memberOf microstrategy
 * @param {HTMLElement} elem The HTMLElement with which to begin the search.
 * @param {String|String[]} tagName The target tag name or a list of target tag names.
 * @param {String} sAtt The target attribute name.
 * @param {String} sAttValue The target attribute value.
 * @returns {HTMLElement} The start HTMLElement or found HTMLElement, or null if not found.
 */
microstrategy.findChildWithAtt = function(elem, tagName, sAtt, sAttValue) {
    //@class=microstrategy;@method=findChildWithAtt;
    try {
        if (!elem) return null;
        if (typeof(tagName) != 'object') tagName = [ tagName ];
        for (var j = 0; j < tagName.length; j++) {
            if ((elem.tagName != null && tagName[j] != null && elem.tagName.toLowerCase() == tagName[j].toLowerCase()) && (elem.getAttribute(sAtt) == sAttValue))
                return elem;
            var objs = elem.getElementsByTagName(tagName[j]);
            if (objs && objs.length) {
                for (var i = 0; i < objs.length; i++) {
                    if (objs[i].getAttribute(sAtt) != null && (objs[i].getAttribute(sAtt).toString()).toLowerCase() == sAttValue.toLowerCase()) {
                        return objs[i];
                    }
                }
            }
        }
        return null;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Finds the parent node with given tag name.
 * @memberOf microstrategy
 * @param {HTMLElement} elem The HTMLElement with which to begin search.
 * @param {String} tagName The target tag name.
 * @returns {HTMLElement} The found HTMLElement node or null.
 */
microstrategy.findParentWithTag = function(elem, tagName) {
    //@class=microstrategy;@method=findParentWithTag;
    try {
        var parent = elem.parentNode;
        while(parent != null) {
            if(parent.tagName && parent.tagName.toLowerCase() == tagName){
                return parent;
            }
            parent = parent.parentNode;
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Finds the node that has the given tag name and object type (the value of 'ty' attribute).
 * @memberOf microstrategy
 * @param {HTMLElement} elem The HTMLElement with which to begin search.
 * @param {String} tagName The target tag name.
 * @param {String} objtType The target object type.
 * @returns {HTMLElement} The found HTMLElement node or null.
 */
microstrategy.objectFind = function(elem, tagName, objtype) {
    //@class=microstrategy;@method=objectFind;
    try {
        return microstrategy.findChildWithAtt(elem,tagName,microstrategy.HTMLATTR_OBJTYPE, objtype);
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Finds the node list that has the given tag name and object type (the value of 'ty' attribute).
 * @memberOf microstrategy
 * @param {HTMLElement} elem The HTMLElement with which to begin search.
 * @param {String} tagName The target tag name.
 * @param {String} objtType The target object type.
 * @returns {HTMLElement[]} The found HTMLElement list or null.
 */
microstrategy.objectListFind = function(elem, tagName, objtype) {
    //@class=microstrategy;@method=objectListFind;
    try {
        return microstrategy.findChildrenWithAtt(elem,tagName,microstrategy.HTMLATTR_OBJTYPE, objtype);
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Finds the node that has the given tag name and sub object type (the value of 'sty' attribute).
 * @memberOf microstrategy
 * @param {HTMLElement} elem The HTMLElement with which to begin search.
 * @param {String} tagName The target tag name.
 * @param {String} objtType The target sub object type.
 * @returns {HTMLElement} The found HTMLElement node or null.
 */
microstrategy.subObjectFind = function(elem, tagName, objtype) {
    //@class=microstrategy;@method=subObjectFind;
    try {
        return microstrategy.findChildWithAtt(elem,tagName,microstrategy.HTMLATTR_SUBOBJTYPE, objtype);
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Finds the node list that has the given tag name and sub object type (the value of 'sty' attribute).
 * @memberOf microstrategy
 * @param {HTMLElement} elem The HTMLElement with which to begin search.
 * @param {String} tagName The target tag name.
 * @param {String} objtType The target sub object type.
 * @returns {HTMLElement[]} The found HTMLElement node list or null.
 */
microstrategy.subObjectListFind = function(elem, tagName, objtype) {
    //@class=microstrategy;@method=subObjectListFind;
    try {
         return microstrategy.findChildrenWithAtt(elem,tagName,microstrategy.HTMLATTR_SUBOBJTYPE, objtype);
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Gets coordinate-rectangle of the given HTMLElement.
 * @memberOf microstrategy
 * @param {HTMLElement} vObject The HTMLElement to measure.
 * @returns {Object} The rectangle object with left, top, right, and bottom attributes.
 * @refactoring Replace the deprecated functions (getObjSumLeft, getObjSumTop, getObjWidth, and getObjHeight). The
 * function is called in doc.js and docSelections.js. Refactor it to be a function in doc.js.
 */
microstrategy.getRect = function(obj) {
    //@class=microstrategy;@method=getRect;
    //Purpose: get coordinate-rectangle of the given object.
    try {
        if (obj) {
            var oRect = new Object;
            oRect.left = getObjSumLeft(obj);
            oRect.top = getObjSumTop(obj);
            oRect.right = oRect.left + getObjWidth(obj);
            oRect.bottom = oRect.top + getObjHeight(obj);
            return oRect;
        }
        return null;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Checks whether to rectangles intersect.
 * @memberOf microstrategy
 * @param {Rect} r1 The rectangle object.
 * @param {Rect} r2 The rectangle object.
 * @returns {Boolean} true if two rectangles intersect, otherwise false.
 */
microstrategy.doRectsIntersect = function(r1, r2) {
    //@class=microstrategy;@method=doRectsInstersect;
    try {
        return (r2.left < r1.right && r2.right > r1.left && r2.top < r1.bottom && r2.bottom > r1.top);
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

/**
 * Checks whether the second rectangle r2 is inside of the first rectangle r1.
 * @memberOf microstrategy
 * @param {Rect} r1 The outer rectangle object.
 * @param {Rect} r2 The inner rectangle object.
 * @returns {Boolean} true if r2 is in r1, otherwise false. 
 * @refactoring Used only once in docSelections.js. Refactor to an inline method.
 */
microstrategy.isRectInRect = function(r1, r2) {
    //@class=microstrategy;@method=isRectInRect;
    try {
        return (r1.left > r2.left && r1.right < r2.right && r1.top > r2.top && r1.bottom < r2.bottom);
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

/**
 * Gets the coordinate of the grid that aligns with given position one direction.
 * @memberOf microstrategy
 * @param {Integer} x The given position.
 * @param {HTMLElement} parentNode The grid node.
 * @param {Boolean} isVertical Flag indicating whether checking the alignment in vertical
 * @param {Boolean} useSnap Indicating whether use the grid for alignment.
 * @param {Integer} direction The direction of the coordinate. 1 indicating positive direction, -1 indicating negative direction.
 * @returns {Integer} the coordinate of the grid that aligns with the given position in one direction.
 */
microstrategy.relativeSnapCoordinate = function(x, parentNode, isVertical, useSnap,direction) {
    //@class=microstrategy;@method=relativeSnapCoordinate;
    try {
        var offset = (isVertical) ? getObjSumTop(parentNode) : getObjSumLeft(parentNode);
        if(!useSnap)
            return x;
        return this.snapCoordinate(x, offset, useSnap, direction);
    }
    catch(err) {
        microstrategy.errors.log(err);
        return x;
    }
}

/**
 * Checks whether given position x is aligned with the grid. 
 * @memberOf microstrategy
 * @param {Integer} x The given position.
 * @param {HTMLElement} parentNode The grid node. 
 * @param {Boolean} isVertical indicating whether checking the alignment in vertical
 * @returns {Boolean} true if x is aligned with the grid.
 * @refactoring In the exception handling, it returns x instead of false. Meanwhile, it is used only 
 * once in docSelections.js. Refactor to an inline method.
 */
microstrategy.isSnapped = function(x, parentNode, isVertical) {
    //@class=microstrategy;@method=isSnapped;
    try {
        var offset = 0;
        if(parentNode != null){
            offset = (isVertical) ? getObjSumTop(parentNode) : getObjSumLeft(parentNode);
        }
        return (((x-offset)%microstrategy.SNAP_SIZE) == 0);
    }
    catch(err) {
        microstrategy.errors.log(err);
        return x;
    }
}

/**
 * Gets the coordinate of the grid that aligns with given position considering offset.
 * @memberOf microstrategy 
 * @param {Integer} x The given position.
 * @param {Integer} offset The offset to the given position.
 * @param {Boolean} useSnap Indicating whether use the grid for alignment.
 * @param {Integer} direction The direction of coordinate. 1 indicating positive direction, -1 indicating negative direction.
 * @returns {Integer} the coordinate of the grid that aligns with the given position in one direction.
 */
microstrategy.snapCoordinate = function(x, offset, useSnap, direction) {
    //@class=microstrategy;@method=snapCoordinate;
    try {
        var relative = x - offset;
        if(useSnap != null && useSnap == false) return relative;

        var moveDistance = 0;
        var rtn = x;
        if(relative%microstrategy.SNAP_SIZE != 0){
            if (direction != null){
                 moveDistance = (direction == microstrategy.SNAP_DIRET_POS)? (microstrategy.SNAP_SIZE - relative%microstrategy.SNAP_SIZE):(relative%microstrategy.SNAP_SIZE)*microstrategy.SNAP_DIRET_NEG;
                 rtn += moveDistance;
            }
            else{
                moveDistance = relative%microstrategy.SNAP_SIZE;
                if (moveDistance > microstrategy.SNAP_SIZE/2) moveDistance = moveDistance - microstrategy.SNAP_SIZE;
                rtn -= moveDistance;
            }
        }
        return rtn;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return x;
    }
}

/**
 * Creates an array object to store the elements. If the given element is a single object, 
 * the object is put into 'item' attribute.
 * @memberOf microstrategy
 * @param {Object|Object[]} elem The source element object(s).
 * @returns {Array} An array object which contains all the elements from source element.
 */
microstrategy.createAssociativeArray = function(elem) {
    //@class=microstrategy;@method=createAssociativeArray;
    try {

        if (elem == null) return null;
        var items = {};
        if (!elem.length) {
        items.item = elem;
        } else {
            for (var i = 0; i < elem.length; i++) {
                items[i] = elem[i];
            }
        }

        return items;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return elem;
    }
}

/**
 * Checks if the src is a dnd (drag-and-drop) mask, and if so returns the associated bone object.
 * @memberOf microstrategy
 * @param {HTMLElement} src The HTMLElement with which to begin search
 * @returns {mstrBoneImpl} The found bone object or null. 
 */
microstrategy.boneForMask = function(src) {
    //@class=microstrategy;@method=boneForMask;
//Checks if the src is a dnd mask, and if so
//returns the associated bone.
    if (!src) return null;

    var type = src.getAttribute(microstrategy.HTMLATTR_OBJTYPE);
    var bone = null;
    if (type == microstrategy.OBJTYPE_MASK || type == microstrategy.OBJTYPE_MASK_MAP){
        bone = microstrategy.bone(src.getAttribute(microstrategy.HTMLATTR_MASKEDOBJECT));
        if(bone == null)
            bone = microstrategy.findBone(document.getElementById(src.getAttribute(microstrategy.HTMLATTR_MASKEDOBJECT)));
    }
    else if (type == microstrategy.OBJTYPE_MASK_MAP_AREA)
        bone = microstrategy.bone(src.parentNode.getAttribute(microstrategy.HTMLATTR_MASKEDOBJECT));
    return bone;
}

/**
 * Adds the event to changes the value of the browser setting into the update manager.
 * @memberOf microstrategy
 * @param {String} name The value of the name parameter of the event.
 * @param {String} value The value of the value parameter of the event.
 * @refactoring Remove 'return elem;' in exception handling.
 */
microstrategy.updateBrowserSetting = function(name, value) {
    //@class=microstrategy;@method=updateBrowserSetting;
    //Adds the event to changes the value of the browser setting
    // into the update manager.
    try {
        if (typeof(mstrUpdateManager) != 'undefined' && mstrUpdateManager.SET_PERMANENT_BROWSER_SETTING) {
            this.updateManager.add([this.updateManager.createActionObject(
                null,
                mstrUpdateManager.SET_PERMANENT_BROWSER_SETTING, microstrategy.servletName + "." + microstrategy.pageName,
                ["5005", "5007"], [name, value], [])], true);
        }
    } catch(err) {
        microstrategy.errors.log(err);
        return elem;
    }
}

/**
 * Updates the values of the cookies in the event that the user navigates away from the page and there are unsent items in the
 * update manager that require updating the cookie.
 * 
 * @memberOf microstrategy
 * @param (String) name The value of the name parameter in the cookie.
 * @param (String) value The value of the value parameter in the cookie. 
 */
microstrategy.updateCookieSetting = function(name, value) {
    //@class=microstrategy;@method=updateCookieSetting;
    
    try {
    	var toUpdate = name + microstrategy.ENCODED_EQUALS,
    		oldValue = toUpdate + (microstrategy.getCookieSetting(name) || 0),
    		newValue = toUpdate + value;
    	
    	//Update cookie values.
        document.cookie = document.cookie.replace(oldValue, newValue);
        
    } catch(err) {
        microstrategy.errors.log(err);
        return elem;
    }
}

/**
 * Returns the values of the cookies stored on the user's computer.
 * 
 * @memberOf microstrategy
 * @param (String) name The value of the name parameter in the cookie for which the value needs to retreived.
 * @return (String) value The value of the value parameter in the cookie. 
 */
microstrategy.getCookieSetting = function(name) {
    //@class=microstrategy;@method=getCookieSetting;
    
    try {
    	return microstrategy.getCookieList()[name];
        
    } catch(err) {
        microstrategy.errors.log(err);
        return elem;
    }
}

/**
 * Parses the value of the document.cookie, and returns a JSON object with the name value pairs.  
 * 
 * @memberOf microstrategy
 * @return (Object) The list of name value pairs in document.cookie.
 */
microstrategy.getCookieList = function() {
    //@class=microstrategy;@method=getCookieList;
    
    try {
    	var cookie = document.cookie,
    		cookieList = [],
    		s = null;
    	
    	//Find the cookie stored by microstrategy.
    	cookie = cookie.split(";");
    	for (s in cookie) {
    		if (cookie[s].indexOf("bSet") >= 0) {
    			cookie = cookie[s];
    			break;
    		}
    	}
    	
    	//Extract the old value of the cookie.
    	cookie = cookie.replace("bSet=", "").split(microstrategy.ENCODED_AMPERSAND);
    	
    	//update the cookie values and stores it in a list.
    	for (s in cookie) {
    		s = cookie[s].split(microstrategy.ENCODED_EQUALS);
    		cookieList[s[0]] = s[1];
    	}
    	
    	//Return the updated cookie list.
    	return cookieList;
    	
    } catch(err) {
        microstrategy.errors.log(err);
        return elem;
    }
}


/**
 * Checks whether the current value is in the filterValue string.
 * @memberOf microstrategy
 * @param {String|Integer} currentValue The value to be found.
 * @param {String} filterValue A string that contains a list of value, separated with ','.
 * @param {String|Integer} filterComparion 
 * @returns {Boolean} true if the current value is in the filterValue string, otherwise false. 
 */
microstrategy.isValueInFilter = function(currentValue, filterValue, filterComparison) {
    //@class=microstrategy;@method=isValueInFilter;
    var toReturn = true;
    try {
        if (currentValue!=null && filterValue!=null) {
            // separate filter by commas
            toReturn = false;
            if (!filterComparison || (filterComparison == microstrategy.HTMLATTR_FILTER_COMPARISON_DEFAULT)) {
                // Split value, compare exact value
                var values = filterValue.split(',');
                var index = 0;
                while (index<values.length && !toReturn) {
                        toReturn = (values[index] == currentValue);
                        index++;
                }
            } else {
                // Binary comparison
                toReturn = parseInt(currentValue) & parseInt(filterValue);
            }
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
    return toReturn;
}

/**
 * Adjusts user palette to add a new color.
 * @memberOf microstrategy
 * @param {String} newColor The new color to be added. It is in '#FFEEDD' format.
 * @returns {String} A string that contains the list of colors that has been added (separated with ',').
 * @refactoring Used only in one place (in mstrColorPickerEditorImpl.js). Refactor to an inline method.   
 */
microstrategy.adjustUserPalette = function(newColor) {
    //@class=microstrategy;@method=adjustUserPalette;
    try {
        var updated = false;
        var colors = this.userPalette;
        if (colors.length == 0) {
            colors = newColor
            updated = true;
        } else {
            // check the color is not already there...
            if (colors.indexOf(newColor) < 0) {
                var tempColors = colors.split(",");
                if (tempColors.length == 8) {
                    // remove the first one, add the new one as last one
                    colors = colors.substr(8,colors.length);
                }
                colors += "," + newColor;
                updated = true;
            }
        }

        if (updated) this.userPalette = colors;

        return (updated) ? colors : null;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Gets a {@link mstrFormatObject}. It will create a new {@link mstrFormatObject} 
 * if the object has not been created before.
 * @memberOf microstrategy
 * @returns {mstrFormatObject} The {@link mstrFormatObject} object.
 */
microstrategy.getFormatObject = function() {
    //@class=microstrategy;@method=getFormatObject;
    try {
        if (this.formatObj == null) {
                this.formatObj = mstrFormatObject;
        }
        return this.formatObj;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Gets the formated property name and value.
 * @memberOf microstrategy
 * @param {String} formatId The command id of formatting.
 * @param {String} formatValue The value of the format command.
 * @returns {Array} An array containing two items. The first item is the 
 * formated property name and the second one is the value. 
 * @refactoring It is actually used in docSelections.js used by mstrDocSelectionsImpl.prototype.setSingleFormat.
 * It's better to put the implementation there.
 */
microstrategy.setSingleFormat = function(formatId, formatValue) {
    //@class=microstrategy;@method=setSingleFormat;
    try {
        var toReturn = [];
        var prop = formatId;
        var value = formatValue;
        var formatObj = mstrFormatObject;
        switch(formatId) {
            case 'Bold':
                    prop = 'fontWeight';
                value = (formatValue) ? 'bold' : 'normal';
                break;
            case 'Italic':
                    prop = 'fontStyle';
                value = (formatValue) ? 'italic' : 'normal';
                break;
            case 'Underline':
                    prop = 'textDecoration';
                value = (formatValue) ? 4 : -4;
                break;
            case 'StrikeOut':
                prop = 'textDecoration';
                value = (formatValue) ? 8 : -8;
                break;
                                
            case 'fstyle':
                if (parseInt(formatValue) & 1) {
                    return microstrategy.setSingleFormat('Bold', formatValue);
                }
                else if (parseInt(formatValue) & 2) {
                    return microstrategy.setSingleFormat('Italic', formatValue);
                }
                else {
                    return microstrategy.setSingleFormat('Underline', formatValue);
                }
                break;

            case 'TextAlign':
            case 'align':
                prop = 'textAlign';
                value = formatObj.decodeValue(prop, formatValue);
                break;

            case 'Horizontal':
                prop = 'textAlign';
                value = formatObj.decodeValue(prop, formatValue);
                break;
            case 'GridHorizontal':
                prop = 'textAlign2';
                value = formatObj.decodeValue(prop, formatValue);
                break;    
                
            case 'Vertical2':
                prop = 'verticalAlign2';
                value = formatObj.decodeValue(prop, formatValue);
                break;
            case 'Vertical':
                prop = 'verticalAlign';
                value = formatObj.decodeValue(prop, formatValue);
                break;
            case 'FontFamily':
            case 'font':
            case 'Name':
                prop = 'fontFamily';
                break;

            case 'FontSize':
            case 'fsize':
            case 'Size':
                prop = 'fontSize';
                value = formatObj.decodeValue(prop, formatValue);
                break;

            case 'bgcolor':
            case 'FillColor':
                if (formatValue == null || formatValue.length == 0){
                    prop = 'backgroundColor';
                    value = "transparent";
                }else{
                    if( formatValue.indexOf(",") >= 0){
                        prop = 'Gradient';
                    } else {
                        prop = 'backgroundColor';
                    }
                }
                break;
            case 'FillStyle':
                prop = 'backgroundStyle';
                if(formatValue == null || formatValue.length == 0) {
                    value = 'transparent';
                }
                if(formatValue && formatValue.indexOf(",") > 0 ) {
                    value = 'Gradient';
                }
                break;
            case 'LineSpacing':
                prop = 'lineHeight';
                if (formatValue == "0") formatValue = 'normal';
                if (formatValue != 'normal') formatValue += 'in';
                value = formatValue;
                break;
            case 'selectionColor':
                prop = 'selectionColor';
                value = (formatValue == 'automatic')? '#60b1f6':formatValue;
                break;
            case 'selectionStyle':
                prop = 'selectionStyle';
                value = (formatValue == 'automatic')? '0':'1';
                break;
            case 'LeftPadding':
            case 'TopPadding':
            case 'RightPadding':
            case 'BottomPadding':
                prop = 'paddingLeft';
                if (formatId == 'RightPadding') prop = 'paddingRight';
                if (formatId == 'BottomPadding') prop = 'paddingBottom';
                if (formatId == 'TopPadding') prop = 'paddingTop';
                value = formatValue+'pt';
                break;

            case 'TextWrap':
                prop = 'whiteSpace';
                value = (formatValue > 0) ? 'normal' : 'nowrap';
                break;

            case 'color':
            case 'Color':
            case 'FontColor':
                prop = 'color';
                break;

            case 'TopColor':
            case 'LeftColor':
            case 'RightColor':
            case 'BottomColor':
                prop = 'borderTopColor';
                if (formatId == 'LeftColor') prop = 'borderLeftColor';
                if (formatId == 'RightColor') prop = 'borderRightColor';
                if (formatId == 'BottomColor') prop = 'borderBottomColor';
                break;

            case 'TopStyle':
            case 'LeftStyle':
            case 'RightStyle':
            case 'BottomStyle':
                prop = 'borderTopStyle';
                if (formatId == 'LeftStyle') prop = 'borderLeftStyle';
                if (formatId == 'RightStyle') prop = 'borderRightStyle';
                if (formatId == 'BottomStyle') prop = 'borderBottomStyle';
                switch (formatValue){
                    case "0":
                    case "5":
                    case "1":
                    case "7":
                        value = "solid";
                        break;
                    case "3":
                        value = "dashed";
                        break;
                    case "4":
                        value = "dotted";
                        break;
                    case "6":
                        value = "double";
                        break;
                }
                break;

                case 'topWidth':
                case 'leftWidth':
                case 'rightWidth':
                case 'bottomWidth':
                    prop = 'borderTopWidth';
                    if (formatId == 'leftWidth') prop = 'borderLeftWidth';
                    if (formatId == 'rightWidth') prop = 'borderRightWidth';
                    if (formatId == 'bottomWidth') prop = 'borderBottomWidth';
                    switch (formatValue){
                        case "0":
                            value = "0pt";
                            break;
                        case "3":
                        case "4":
                        case "1":
                        case "7":
                            value = "1pt";
                            break;
                        case "5":
                            value = "1.5pt";
                            break;
                        case "6":
                            value = "2.5pt";
                            break;
                    }
                    break;
                    
                case 'HasDropShadow':
                    prop = "dropShadowEffect";
                    value = (value) ? "1" : "0";
                    break;

                case 'HasRoundedCorners':
                    prop = "hasRoundedCorners";
                    value = (value) ? "-1" : "0";
                    break;
                    
                case 'DropShadow':
                    prop = "dropShadowDepth";
                    break;
                    
                case 'TopCornersOnly':
                    prop = "topCornersOnly";
                    break;
        }
        toReturn[0] = prop;
        toReturn[1] = value;
        return toReturn;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Checks the action list of given HTMLElement. If the HTMLElement contains the action in the given action list,
 * it returns true. Otherwise, it returns false.
 * @memberOf microstrategy
 * @param {HTMLElement} elem The given HTMLElement for 'acl' attribute check.
 * @param {Array} aclList The action list array. 
 * @returns {Boolean} If the value of the 'acl' attribute in the HTMLElement is in the given action list array,
 * it returns true. Otherwise, it returns false.
 */
microstrategy.checkACL = function(elem, aclList) {
    //@class=microstrategy;@method=checkACL;
    try {
        if (elem && aclList) {
            var acl = elem.getAttribute(microstrategy.HTMLATTR_ACL);
            if (acl && acl.length > 0) {
                   var iAcl = parseInt(acl);
                for (var i = 0; i < aclList.length; i++) {
                    if ((parseInt(aclList[i]) & iAcl) == 0) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Checks whether the given type is a valid group by type. Valid group by types are consolidation, filter, and attribute.
 * @memberOf microstrategy
 * @param {String} dssType The name of the type for check.
 * @returns {Boolean} true if the given type is a valid group type or false if it is not.
 */
microstrategy.isValidGroupByType = function(dssType) {
    //@class=microstrategy;@method=isValidGroupByType;
    try {
        if (dssType == microstrategy.DSSTYPE_CONSOLIDATION ||
                dssType == microstrategy.DSSTYPE_FILTER || //custom groups
                dssType == microstrategy.DSSTYPE_ATTRIBUTE ){
                return true;
            }
            return false;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

/**
 * Toggles the editor that is associated with given bone or bean. 
 * @memberOf microstrategy
 * @param {String} boneId The bone id.
 * @param {String} beanName The bean name of the editor if the bone cannot be found.
 * @param {Boolean} doNotSubmit The flag indicates whether the updateManager should submit the changes immediately. The
 * value sets to be false when the changes need to submit immediately. 
 * @returns {Boolean} true if no exception otherwise false.
 */
microstrategy.toggleEditor = function(boneId, beanName, doNotSubmit) {
    //@class=microstrategy;@method=toggleEditor;
    try {
        var b = this.bone(boneId);

        if (b) {
            b.closeEditor();
        } else {
            var updateManager = this.updateManager;

            var actionCollection = [];
            actionCollection.push(
                updateManager.createActionObject(this, mstrUpdateManager.SHOW_BEAN,
                                                 microstrategy.servletName + "." + microstrategy.pageName,
                                                 ["5017", "5018"],
                                                 [true, beanName], []));
            updateManager.add(actionCollection);
            if ( ! doNotSubmit ) {
                updateManager.flushAndSubmitChanges();
            }
        }

        return true;

    } catch (err) {
        microstrategy.errors.log(err);
        return false;
    }

}

/**
 * Shows the accordion on the wait page of Report/RW. It shows the related reports area 
 * (if necessary) with a fixed width as no bones are registered while waiting.
 * @memberOf microstrategy
 * @param {String} cellId The id of the cell to be displayed.
 * @param {String} containerId The id of the container to be displayed.
 */
microstrategy.showAccordionWhileWaiting = function(cellId, containerId) {
    //@class=microstrategy;@method=showAccordionWhileWaiting; 
    //This is used on the wait page of Report/RW, to show the related reports area (if necessary) with a fixed width as no bones are registered while waiting...
    try {
        if(!cellId) cellId = 'td_mstrWeb_dockLeft';
        if(!containerId) containerId = 'mstrWeb_dockLeft';
        var accordion = document.getElementById('accordion_AccordionTabManagerStyle');
        if(accordion){
           var leftCell = document.getElementById(cellId);
           if(leftCell) {
             leftCell.style.display = 'block';
             leftCell.style.width = '220px';
           }
           var leftDiv = document.getElementById(containerId);
           if(leftDiv) leftDiv.style.display = 'block';
           var closeBtn = microstrategy.findChildWithAtt(accordion, 'IMG', (bIsW3C)? 'class': 'className', 'mstrIcon-btn mstrIcon-btnClose');
           if(closeBtn) closeBtn.style.display = 'none';
           accordion.style.width = '220px';
           if(bIsIE6) {
              accordion.style.position = 'relative';
              var relatedReportsDiv = document.getElementById('relatedReportsId');
              if(relatedReportsDiv) relatedReportsDiv.style.width = '210px';
           }
        }
    } catch (err) {
        microstrategy.errors.log(err);
        return false;
    }
}

/**
 * Toggles the accordion. It also adds/removes the notes icon from the toolbar according to the existence of accordion.
 * @memberOf microstrategy
 * @param {String} curTab The tab name of the accordion needs to be enabled.
 * @param {String} canTurnOff 
 * @returns {Boolean} true if no exception, otherwise false.
 */
microstrategy.toggleAccordion = function(curTab, canTurnOff) {
    //@class=microstrategy;@method=toggleAccordion;
    try {
        var b = this.bone('accordion_AccordionTabManagerStyle');
        var cookieName = 'lTbar';
        canTurnOff = (typeof(canTurnOff)!='undefined' && !canTurnOff)? false:true;
        
        if(microstrategy.EXECUTION_SCOPE == microstrategy.RWD_EXECUTION){
            cookieName = (microstrategy.DISPLAY_MODE == microstrategy.DESIGN_MODE)? 'obDesign':'obView';
        } else if(microstrategy.EXECUTION_SCOPE == microstrategy.REPORT_EXECUTION){
            cookieName = 'accordionReportView';
        }
        if (b && (b.currentTabName == curTab || typeof(curTab) == 'undefined') && canTurnOff) {
            // the left accordion should never be turned off in report design mode
            if(microstrategy.EXECUTION_SCOPE != microstrategy.REPORT_EXECUTION || microstrategy.DISPLAY_MODE != microstrategy.DESIGN_MODE){
                this.updateBrowserSetting(cookieName, '0');
                b.closeEditor(false);
                var notesIconModel = mstr.$obj('NotesIconModel_model');
                
                if(notesIconModel){
                    if(notesIconModel.get('objectID') && notesIconModel.get('objectType')){ 
                        notesIconModel.execCheck();
                    }
                    else{
                        var notesIconView = mstr.$obj('NotesIconView_view');
                        if(notesIconView)
                            notesIconView.set('visible', false);
                    }
                    
                }
            }
        } else if (b){
            b.setCurTab(curTab);
        } else {
            this.updateBrowserSetting(cookieName, '1');
            if(typeof(curTab)!='undefined') this.updateBrowserSetting((microstrategy.EXECUTION_SCOPE == microstrategy.RWD_EXECUTION)? 'accordionRWTab':'accordionReportTab', curTab);
            toggleShowBean("accordion", true, (typeof(curTab)!='undefined')?"currentTabName="+curTab:"");
            var notesPanelName = (microstrategy.EXECUTION_SCOPE == microstrategy.REPORT_EXECUTION)? microstrategy.ACCORDION_REPORT_NOTES_PANEL:microstrategy.ACCORDION_RW_NOTES_PANEL;
            if(curTab == notesPanelName) {
               var notesIconView = mstr.$obj('NotesIconView_view');
               if(notesIconView) notesIconView.set('visible', false);
            } else {
               var notesIconModel = mstr.$obj('NotesIconModel_model');
               if(notesIconModel){
                    if(notesIconModel.get('objectID') && notesIconModel.get('objectType')) 
                        notesIconModel.execCheck();
                }
            }
        }

        return true;

    } catch (err) {
        microstrategy.errors.log(err);
        return false;
    }

}

/**
 * Check whether the report bone's needSaveBeforeNotes field is set to be true of not.
 * @memberOf microstrategy
 * @returns {Boolean} It returns the value of needSaveBeforeNotes filed in the report bone. 
 */
microstrategy.needSaveBeforeNotes = function() {
    //@class=microstrategy;@method=needSaveBeforeNotes;
    try{
       var bone = ((microstrategy.EXECUTION_SCOPE == microstrategy.REPORT_EXECUTION)? microstrategy.bone("UniqueReportID"):microstrategy.getViewerBone());
       return (bone && bone.needSaveBeforeNotes);
    } catch (err) {
        microstrategy.errors.log(err);
        return false;
    }
}

/**
 * Performs the save action on the current report or document.
 * @memberOf microstrategy
 * @returns {Boolean} true if save action is executed successfully. Otherwise, it returns false.
 * @refactoring Used only once in mstrNotesTabImpl.js. Refactor to an inline method.
 */
microstrategy.performSave = function() {
    //@class=microstrategy;@method=performSave;
    try{
       if(microstrategy.EXECUTION_SCOPE == microstrategy.REPORT_EXECUTION){                 //report
          var rb = microstrategy.bone("UniqueReportID");
          return (rb && rb.commands.exec("save"));
       } else if(microstrategy.EXECUTION_SCOPE == microstrategy.RWD_EXECUTION) {            //document
          var rwbv = microstrategy.bone("rwb_viewer");
          return (rwbv && rwbv.doc.commands.exec("save"));
       }
    } catch (err) {
        microstrategy.errors.log(err);
        return false;
    }
}

/**
 * Toggles the related reports panel. If the left toolbar does not show up, it enables the left toolbar.
 * @memberOf microstrategy
 * @returns {Boolean} true if no exception or false if there is an exception.
 */
microstrategy.toggleRelatedReports = function() {
    //@class=microstrategy;@method=toggleRelatedReports;
    try {
        var b = this.bones['relatedReports'];

    if (b) {
        this.updateBrowserSetting('lTbar', '0');
    } else {
        this.updateBrowserSetting('lTbar', '1');
    }
           
    this.updateManager.useIframe = false;
    this.updateManager.flushAndSubmitChanges();
    
    return true;

    } catch (err) {
        microstrategy.errors.log(err);
        return false;
    }

}

/**
 * Toggles the left toolbar.
 * @memberOf microstrategy
 * @returns {Boolean} Returns false always.
 * @refactoring The function always returns false which makes no sence. 
 */
microstrategy.toggleLeftToolbar= function() {
    //@class=microstrategy;@method=toggleEditor;
    try {
        var b = this.bone('leftToolbar');
        if (b) {
            b.close();
        } else {
            
            this.updateBrowserSetting('lTbar', '1');
            this.updateManager.useIframe = false;
            this.updateManager.flushAndSubmitChanges();
        }

        return false;

    } catch (err) {
        microstrategy.errors.log(err);
        return false;
    }

}

/**
 * Disables the text selection in both IE and Firefox.
 * @memberOf microstrategy
 * @param {HTMLElement} target The target HTMLElement to be set.
 * @refactoring Used only in one place in mstrFolderFrameTreeViewImpl.js Refactor to an inline method.
 */
microstrategy.disableTextSelection = function(target){
	//@class=microstrategy;@method=disableTextSelection;
	//This is used to disable text selection in both IE and Firefox.
	try {
		if (!target) return;
		if (typeof target.onselectstart!="undefined") {//IE
			target.onselectstart=function(){return false}
		} else if (typeof target.style.MozUserSelect!="undefined") {//Firefox
			target.style.MozUserSelect="none";
		}
	} catch (err) {
		microstrategy.errors.log(err);
	}
}

/////////////////////////////////////////////
mstrAreaObjectImpl.prototype = {};

/**
 * @class A simple object representing a single zone on a mapped mask.
 */
function mstrAreaObjectImpl() {
    this.shape = 'rect';
    this.coords = '0,0,0,0';
    this.pointsTo = null;
    this.onmouseovercoords = null;
    this.onmouseout = null;
    this.moveHilite = true;
}

mstrObjectInfoImpl.prototype = {};
mstrObjectInfoImpl.prototype.src = null;
mstrObjectInfoImpl.prototype.left = 0;
mstrObjectInfoImpl.prototype.top = 0;
mstrObjectInfoImpl.prototype.height = 0;
mstrObjectInfoImpl.prototype.width = 0;
mstrObjectInfoImpl.prototype.alias = "";
mstrObjectInfoImpl.prototype.dssId = "";
mstrObjectInfoImpl.prototype.dssFrmId = "";
mstrObjectInfoImpl.prototype.dssType = 0;
mstrObjectInfoImpl.prototype.dssSubType = 0;
mstrObjectInfoImpl.prototype.dSetId = null;
mstrObjectInfoImpl.prototype.dSetName = "";
mstrObjectInfoImpl.prototype.isUnique = true;

/**
 * @class A simple object representing a MicroStrategy meta data object.  The values for the fields on this object are harvested from the attributes of the HTMLElement that
 *      is passed into the constructor.
 * @param {HTMLElement} elem The element that this instance should be based on.  
 */
function mstrObjectInfoImpl(elem) {
    //@class=mstrObjectInfoImpl;@method=constructor;
    try {
        if (elem) {
            this.src = elem;
            this.alias = elem.getAttribute("ds");
            var bone = microstrategy.findBone(elem);
            if (!bone) {
                var subtype = elem.getAttribute(microstrategy.HTMLATTR_SUBOBJTYPE);
                if (subtype == microstrategy.SUBOBJTYPE_ATTRIBUTE || subtype == microstrategy.SUBOBJTYPE_ATTRIBUTE_FORM || subtype == microstrategy.SUBOBJTYPE_METRIC) {
                    this.dssId = elem.getAttribute(microstrategy.HTMLATTR_DSS_ID);
                    this.dssType = elem.getAttribute(microstrategy.HTMLATTR_DSS_TYPE);
                }
            } else {
                this.dssType = elem.getAttribute(microstrategy.HTMLATTR_DSS_TYPE);
                this.dssSubType = elem.getAttribute(microstrategy.HTMLATTR_DSS_SUBTYPE);
                if (this.dssType == microstrategy.DSSTYPE_ATTRIBUTE_FORM) {
                    if (bone.type == microstrategy.OBJTYPE_OBJBROWSER) {
                        this.dssFrmId = elem.getAttribute(microstrategy.HTMLATTR_DSS_ID);
                        this.dssId = elem.getAttribute(microstrategy.HTMLATTR_ATTRIBUTE_ID);
                    }
                } else {
                    this.dssId = elem.getAttribute(microstrategy.HTMLATTR_DSS_ID);
                }
                switch (bone.type) {
                    case microstrategy.OBJTYPE_OBJBROWSER:
                        this.dSetId = microstrategy.primeDataSetId;
                        if (bone.isRWTab) {
                            this.dSetId = elem.getAttribute("id").slice(0, 32);
                            this.dSetName = bone.getDatasetName(this.dSetId);
                            if (this.dssType == microstrategy.DSSTYPE_METRIC) {
                                this.isUnique = bone.isMetricUnique(this.alias);
                            }
                        }
                        break;
                    case microstrategy.OBJTYPE_PAGE_BY_ELEM:
                        this.dSetId = microstrategy.primeDataSetId;
                        break;
                    case microstrategy.OBJTYPE_DOC_SUBSECTION:
                    case microstrategy.OBJTYPE_DOC_OBJECT:
                        this.dSetId = elem.getAttribute(microstrategy.HTMLATTR_DSS_SET);
                        break;
                }
            }
        }
        return this;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Determines if a particular property is applicable to all the items in the selections.
 * @memberOf microstrategy
 * @param {HTMLElement} items The target HTMLElement object.
 * @param {String} prop The property value.
 * @returns {Boolean} true if one item is found that the property can be applied to or false if no match is found.
 */
microstrategy.isEnabled = function(items, prop) {
    //@class=microstrategy;@method=isEnabled;
    // Usage: Determine if a particular property is applicable to all the items in the selections
    try {
        var format = this.getFormatObject();
        if (items && format[prop]) {
            // Check to see if property applies to all
            if (format[prop][mstrFormatObject.APPLIES_TO] == "all") return true;
            
            // Step through items looking for any item that this property applies to...
                for (var item in items){
                if(this.isEnabledForItem(items[item], prop)) return true;
            }
        }
        // Otherwise, none match so return false.
        return false;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

/**
 * Determines if a particular property is applicable to a particular item in the selections.
 * @memberOf microstrategy
 * @param {HTMLElemen} item  The target HTMLElement object.
 * @param {String} prop The property value.
 * @returns {Boolean} true if the property can be applied to the item.
 */
microstrategy.isEnabledForItem = function(item, prop) {
    //@class=microstrategy;@method=isEnabledForItem;
    // Usage: Determine if a particular property is applicable to a particular item in the selections
    try {
        if(prop == "Gradient") return true;
        var f = this.getFormatObject();
        if (f[prop][mstrFormatObject.APPLIES_TO] == "all") {
            return true;
        }
        var at = f[prop][mstrFormatObject.APPLIES_TO];
        var type = item.getAttribute(microstrategy.HTMLATTR_OBJTYPE);
        var subType = item.getAttribute(microstrategy.HTMLATTR_SUBOBJTYPE);

        if (at.contains(type, ",") || at.contains(subType, ",")) {
                if(subType != microstrategy.SUBOBJTYPE_DOC_SELECTOR_CONTROL || prop != 'textAlign') {
                   return true;
                } else {
                   if(item.firstChild) {
                       var ctlBone = microstrategy.bone(item.firstChild.id);
                       if(ctlBone) {
                          switch(ctlBone.ctlStyle){
                             case mstrRWControlImpl.CTL_STYLE_POOL_DOWN:
                             case mstrRWControlImpl.CTL_STYLE_SCROLLER:
                             case mstrRWControlImpl.CTL_STYLE_LIST_BOX:
                                return false;
                             default:
                                return true;
                                break;
                          }
                       }
                   }
                }
        }
        return false;
        



    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

/**
 * Sets the primeDataSetId variable value.
 * @memberOf microstrategy
 * @param {String} id The new value of primeDataSetId.
 * @refactoring Only used in RWLayoutTransform.java. Put the code there instead of calling the function.
 */
microstrategy.setPrimeDataSetId = function(id){
    microstrategy.primeDataSetId = id;
}

/**
 * Checks whether the specified event handler is existed or not. 
 * @memberOf microstrategy
 * @param path The path string used to break down to check the availability of each object (event handler).
 * @returns {String} A string contains part of the script representing the availability of the objects in the path.   
 */
microstrategy.getEventHandlerString = function(path) {
    //@class=microstrategy;@method=getEventHandlerString;
    try {
        if (typeof(path) != "string" || path.length == 0) {
            return "if (true)";
        }
        var components = path.split(".");
        for (var i = 1; i < components.length; i++) {
            components[i] = components[i - 1] + "." + components[i];
        }
        var delimiter = "";
        var s = "";
        for (var i = 0; i < components.length; i++) {
            s += delimiter + "(typeof(" + components[i] + ") != 'undefined' && " + components[i] + " != null)";
            delimiter = " && ";
        }
        return "if (" + s + ")";
    } catch (err) {
        microstrategy.errors.log(err);
        return "if (true)";
    }
}

/**
 * Checks whether where the object browser is open.
 * @memberOf microstrategy
 * @returns {Boolean} true if the object browser is open. 
 */
microstrategy.isObjectBrowserOpen = function() {
    //@class=microstrategy;@method=isObjectBrowserOpen;
    try {
        for (var id in this.bones) {
            if (this.bones[id].type == microstrategy.OBJTYPE_OBJBROWSER) {
                return true;
            }
        }
    } catch (err) {
        microstrategy.errors.log(err);
    }
    return false;
}

/**
 * Gets the object browser bone object.
 * @memberOf microstrategy
 * @returns {mstrBoneImpl} the object browser bone object.
 * @refactoring Used only once in docSelections.js. Refactor to an inline method.
 */
microstrategy.getObjectBrowser = function() {
    //@class=microstrategy;@method=getObjectBrowser;
    try {
        for (var id in this.bones) {
            if (this.bones[id].type == microstrategy.OBJTYPE_OBJBROWSER) {
                return this.bones[id];
            }
        }
    } catch (err) {
        microstrategy.errors.log(err);
    }
    return null;
}

/**
 * Retrieves the border widths and padding values from given item on the given direction. 
 * @memberOf microstrategy
 * @param {HTMElement} item The HTMLElement for border and padding checking. 
 * @param {String} styleProp The style property. Can be either 'height' or 'width'.
 * @param {String} defFmt The default format object.
 * @returns {Integer[]} An array with four elements holding the border widths and padding values.
 * @refactoring Only called inside the getPaddingAndBorderPixels(). Refactor to an inline method.
 */
microstrategy.retrievePaddingAndBorders = function(item, styleProp, defFmt) {
    //@class=microstrategy;@method=retrievePaddingAndBorders;
    try {
        var values = [];
        var props = [];
        
        // retrieve from Style Object.
        if (item != null) {   
        
            if (styleProp == "height") {
                props = [ 'borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom' ];
            } else {
                props = [ 'borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight' ];
            }
            for (var i = 0; i < 4; i++) {
                values.push(this.styleObj.getValue(item, props[i]));
            }
            
            return values;
        }
       
        // retrieve from default format Object.       
        var fmtInfo = this.getFormatObject();
        
        var obj = {
            ts: "0", bs: "0", tp: "0", bp: "0", 
            ls: "0", rs: "0", lp: "0", rp: "0"
        };
        
        props = [ {
            ps: 'FormattingBorder',
            p: 'Style',
            a: [ 'Top', 'Bottom', 'Left', 'Right' ]
        }, {
            ps: 'FormattingPadding',
            p: 'Padding',
            a: [ 'Top', 'Bottom', 'Left', 'Right' ]
        }, {
            ps: 'FormattingLine',
            p: 'LineWeight'
        }];
        
        var pv, ipv;
        
        for (var i = 0; i < 3; i++) {
            var ps = defFmt[props[i].ps];
            var is = fmtInfo[props[i].ps];
            if (!ps || !is) {
                continue;
            }    
            
            var p = props[i].p;
            var a = props[i].a;
            if (a) {
                for (var j = 0; j < 4; j++) {
                    pv = ps[a[j] + p];
                    ipv = is[a[j] + p];
                    if (!pv || !ipv) {
                        continue;
                    }    
                    
			        var pn = ipv[mstrFormatObject.HTML_PROP_NAME];
			        var dv = fmtInfo.decodeValue(pn, pv.defaultValue||"0");
                    
                    obj[a[j].substr(0, 1).toLowerCase() + p.substr(0, 1).toLowerCase()] = dv;
                }
            } else {
                pv = ps[p];
                ipv = is[p];
                if (!pv ||!ipv) {
                    continue;
                }    
                
                var pn = ipv[mstrFormatObject.HTML_PROP_NAME];
                var dv = fmtInfo.decodeValue(pn, pv.defaultValue||"0");
                
                obj.ts = dv;
                obj.bs = dv;
                obj.ls = dv;
                obj.rs = dv;
            }
        }

        if (styleProp == "height") {
            values = [
                    obj.ts, obj.bs, obj.tp, obj.bp, 
                ];
         } else{
            values = [
                    obj.ls, obj.rs, obj.lp, obj.rp,
                ];
         }       

        return values;
    } catch (err) {
        microstrategy.errors.log(err);
        return [];
    }
}

/**
 * Retrieves the border width and padding value in pixel from given item. The method considers the difference of
 * IE and firefox. 
 * @memberOf microstrategy
 * @param {Object} item HTMLElement The HTMLElement for border and padding checking.
 * @param {String} styleProp The style property. Can be either 'height' or 'width'.
 * @param {String} defFmt The default format object.
 * @returns {Integer} The value of the sum of padding value and border width.
 */
microstrategy.getPaddingAndBorderPixels = function(item, styleProp, defFmt) {
    //@class=microstrategy;@method=getPaddingAndBorderPixels;
    try {
        var values = this.retrievePaddingAndBorders(item, styleProp, defFmt);
        
        var pxs = 0.0;
        var pts = 0.0;
        for (var i = 0; i < values.length; i++) {
            if (values[i] != null && values[i].length > 0 && !isNaN(parseFloat(values[i]))) {

                // IE's logic rounds each border value individually when translating from points to
                // pixels. Under normal scenarios, 1pt equals 1.333px. On the browsers, this is
                // handled differently. For example, a 1pt border for IE it represents 1px each side;
                // for Firefox it will be 1px on one side and 2px on the other side. So for IE you will
                // end up with a 94px rectangle width (plus the 2px from the borders, 96px) and for
                // Firefox, you need to define the same rectangle with a 93px width for it to be 96px
                // total. TQMS 216407
                if (bIsIE6) {
                    pxs += Math.round(this.getFormatObject().getPxFromPt(values[i]));
                } else {
                    pts += parseFloat(values[i]);
                }

            }
        }
        return pxs + this.getFormatObject().getPxFromPt(pts);
    }
    catch(err) {
        microstrategy.errors.log(err);
        return 0;
    }
}

/**
 * Gets the maximum z-index value. 
 * @memberOf microstrategy
 * @returns {Integer} 0 if it is a report page; if the page is a document page, 
 * it returns the maximum z-index from the document bone objects.
 */
microstrategy.getMaxZIndex = function() {
    //@class=microstrategy;@method=getMaxZIndex;
    try {
        var maxZIndex = 0;
        if (this.EXECUTION_SCOPE == microstrategy.REPORT_EXECUTION) {
            return maxZIndex;
        } else {
            var docViewer = this.bone('rwb_viewer');
            if (docViewer != null) {
                if (docViewer.commands && docViewer.commands.exec) {
                    maxZIndex = docViewer.commands.exec('maxZIndex');
                }
            }
        }
        return maxZIndex;

    }
    catch(err) {
        microstrategy.errors.log(err);
        return 0;
    }
}

/**
 *  A helper function that activates a field and sets the focus on it.
 *  @memberOf microstrategy
 *  @param {HTMLElement} field The HTMLElement that needs to be focused.
 */
microstrategy.setCursorToEnd = function(field) {
        // We need to do special actions only for IE as Firefox does it
        // automatically. So we check for the createTextRange method, which
        // is present in IE but abcent in Firefox.
        if (field.createTextRange) {
            var range = field.createTextRange();
            range.moveStart("character", field.value.length);
            range.collapse();
            range.select();
        } else {
            field.focus();
        }
}


/**
 * Creates an action collection for update manager to display a specified dialog.
 * @memberOf microstrategy
 * @param {String} dialogName The dialog name to be displayed.
 * @param {String} url The url to set the update manager extraURL field.
 * @param {Array} actionCollection An array that contains a collection of actions.
 * @param {String} beanPath The path of the bean to include in the request.
 * @param {Object} propsObject The property object used to create a serialized string 
 * @returns {Array} An array that contains a collection of actions or null. 
 * @refactoring In the exception handling part, it should return either the array or null. It should not return false.
 */
microstrategy.openDialog = function(dialogName, url, actionCollection, beanPath, propsObject) {
    //@class=microstrategy;@method=openDialog;
    try {
        var passOut = (actionCollection != null);
        if (!passOut) {
            var actionCollection = [];
        }

        var ids = new Array("5018","5017");
        var values = new Array(dialogName, true);
        if (propsObject) {
            var sm = new mstrSerializer();
            for (var p in propsObject) {
                var pm = new mstrSerializer();
                pm.addStr(p);
                pm.addStr(propsObject[p]);
                sm.addStr(pm.getState());
            }
            ids.push("5024");
            values.push(sm.getState());
        }
        actionCollection.push(this.updateManager.createActionObject(this, mstrUpdateManager.SHOW_BEAN, beanPath, ids, values, [] ));

        if(!passOut) {
            this.updateManager.add(actionCollection);
        }
        this.updateManager.addURL(url);
        return (passOut) ? actionCollection : null;

    }
    catch(err) {
        microstrategy.errors.log(err);
        return (actionCollection != null) ? actionCollection : false;
    }
}

/**
 * Gets an array of bones with specified types.
 * @memberOf microstrategy
 * @param {String|String[]} types Bone type(s).  
 * @returns {mstrBoneImpl[]} An array of bone objects.
 * @refactoring Used only once in docCommands.js. Refactor to an inline method.
 */
microstrategy.getBonesByType = function(types) {
    //@class=microstrategy;@method=getBonesByType;
    try {
        var __result = [];
        var parameterType = typeof(types);
        var typesTestStr = (parameterType.toLowerCase() == "string") ? "~" + types + "~" : "~" + types.join("~") + "~";
        for (var b in this.bones) {
            if (typesTestStr.search("~" + this.bones[b].type + "~") > -1) {
                __result.push(this.bones[b]);
            }
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
    return __result;
}

/**
 * Unregisters the grid bones.
 * @memberOf microstrategy
 * @param {String} type The type name
 * @refactoring The input parameter is never used in the code and it should be removed. Used only 
 * once in viewCommands.js. Refactor to an inline method.
 */
microstrategy.unregisterGridBones = function(type) {
    //@class=microstrategy;@method=unregisterGridBones;
    try {
        for( var id in this.bones){
            var obone = this.bones[id];
            if(obone && obone.elem){
                var obj = obone.elem; 
                var otype = obj.getAttribute(microstrategy.HTMLATTR_SUBOBJTYPE);
                if(otype == microstrategy.SUBOBJTYPE_GRID_TABLE){
                    microstrategy.unRegisterBone(id);
                }
            }
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
}

/**
 * Updates the update manager to add new action to set the given bone with new view mode. 
 * @memberOf microstrategy
 * @param {mstrBoneImpl} bone The given bone object for view mode updating.
 * @param {String} newViewMode The new view mode.
 */
microstrategy.adjustSelectedVisualization = function(bone, newViewMode) {
  //@class=microstrategy;@method=adjustSelectedVisualization;
    try {
        // get the view mode for the selected visualization
        var currVisViewMode;
        for (var i=0;i<bone.visualizationList.length;i++) {
            var name = bone.visualizationList[i].name;
            if (name == bone.selectedVisualization) {
                currVisViewMode = bone.visualizationList[i].vm;
                break;
            }            
        }
        
        if (currVisViewMode == newViewMode) return; // same view mode return
    
        // find the first visualization with the selected view mode on the list
        var firstVisWithViewMode;    
        for (var j=0;j<bone.visualizationList.length;j++) {
            var vm = bone.visualizationList[j].vm;
            if (vm == newViewMode) {
                firstVisWithViewMode = bone.visualizationList[j].name;
                break;
            }
        }
        
        if (firstVisWithViewMode) {
            var actionCollection = [];
            if (bone.setVisualizationSettings) {
                bone.setVisualizationSettings(null, firstVisWithViewMode, null, -1, actionCollection);
            } else if (bone.doc && bone.doc.setVisualizationSettings) {
                bone.doc.setVisualizationSettings(null, firstVisWithViewMode, null, -1, actionCollection);
            }
            this.updateManager.add(actionCollection);
        }
    } catch(err) {
        microstrategy.errors.log(err);
    }
}

/**
 * Updates the visualization properties on the target bone.
 * @memberOf microstrategy
 * @param {Boolean} enabled Sets the visualizationsEnabled field of the target bone.
 * @param {Object} selectedVisualization Sets the selectedVisualization filed of the target bone.
 * @param {Array} visualizationList Sets the visualizationList field of the target bone.
 * @param {String} viewMode Sets the visualizationMode of the target bone. 
 * @param {mstrBoneImpl} bone The target bone object.
 */
microstrategy.updateVisProps = function(enabled, selectedVisualization, visualizationList, viewMode, bone) {
  //@class=microstrategy;@method=updateVisProps;
    try {
        if (enabled) {
            bone.visualizationsEnabled = enabled;
        }
        if (selectedVisualization != null) {
            bone.selectedVisualization = selectedVisualization;
        }
        if (visualizationList != null) {
			var selList = visualizationList.split(",");
			var allVis = bone.getAllVisList();
			if (allVis && selList.length > 0) {
				bone.visualizationList = [];
				for (var i = 0; i < selList.length; i++) {
					var curVisName = selList[i];
					var curVis = allVis[curVisName];
					if (curVis) bone.visualizationList.push({name : curVisName, desc : curVis.d, vm : curVis.vm});
				}
			}
        }
        if (viewMode && viewMode != bone.visualizationMode) {
            bone.visualizationMode = viewMode;
            bone.isVisualization = (viewMode >= 50);
        }
    } catch(err) {
        microstrategy.errors.log(err);
    }
}

/**
 * Repaints the specified HTML table with given grid id.
 * @memberOf microstrategy
 * @param {String} gridId The grid id with which to find the HTML table.
 * @refactoring Called in one place in mstrGridStatic.js. Refactor to an inline method.
 */
microstrategy.repaintContent = function(gridId){
    //@class=microstrategy;@method=repaintContent;
    try {

       // Local function, to be applied possibly twice.
       // Don't use table.cells, that's IE-only.  Instead use table.rows[i].cells[j].
       function repaintCells(table) {
	      // Walks the cells of a given table, resetting the style.height to "0px" then "auto".
	      var rows = table && table.rows,
	      	  rows_len = rows && rows.length || 0;
	      for(var i=0; i < rows_len; i++){
	      	var cells = rows[i].cells,
	      		cells_len = cells.length;
	  		for(var j=0; j < cells_len; j++){
	  			var s = cells[j].style;
	  			s.height = "0px";
	  			s.height = "auto";
	  		}
	      }  		        		
       }

       var gridTable = microstrategy.findAncestorWithAtt(document.getElementById(gridId), (bIsW3C)? 'class': 'className', 'repLayout');
       if(gridTable) repaintCells(gridTable);

       var contentTable = document.getElementById('mstrWebContentTable');
       repaintCells(contentTable);
    } catch(err) {
        microstrategy.errors.log(err);
    }
}

/**
 * A helper function that converts a bitmap flag into an array represents the availability of the four borders.
 * @memberOf microstrategy
 * @param {String} flags The bitmap flag representing the availability of four borders. For example, if flag is 31, it means all borders are there.
 * @param {Boolean} includeSides The boolean value used to specify whether every border flag should be included
 * in the array when the flag is set to be 31.
 * @returns {Integer[]} An integer array representing the existence of the borders. 
 */
microstrategy.resolveBorderFlags = function (flags, includeSides) {
  //@class=microstrategy;@method=resolveBorderFlags;
    var borders = [];
    try {
        if (flags == 0) {
            borders = [ 0 ];
        } else if (flags == 31) {
            borders = [ 16 ];
            if (includeSides) {
                borders = borders.concat(1, 2, 4, 8);
            }
        } else {
            var test = [ 1, 2, 4, 8 ];
            for (i = 0; i < 4; i++) {
                if ((flags & test[i]) > 0) {
                    borders.push(test[i]);
                }
            }
        }
    } catch(err) {
        microstrategy.errors.log(err);
    }
    return borders;
}

/**
 * The method uses the name-value pair from model properties and view properties to overwrite the request parameters.
 * @memberOf microstrategy
 * @param {Object} req A hashtable of name-value pairs, which define the inputs for a request.
 * @param {Object} modelProps A hashtable of name-value pairs, which define properties of the model object.
 * @param {Object} viewProps A hashtable of name-value pairs, which define the properties of the view object.
 */
microstrategy.overwriteRequestParameters = function(req, modelProps, viewProps) {
  //@class=microstrategy;@method=overwriteRequestParameters;
    try {
        var params = req.params || {};
        
        mstr.utils.Hash.overwrite(params, modelProps);
        mstr.utils.Hash.overwrite(params, viewProps);
        
        req.params = params;
    } catch(err) {
        microstrategy.errors.log(err);
    }
}

/**
 *  This method uses the task infrastructure to request a Bean based BlockContainer from the server.
 *  @memberOf microstrategy
 *  @param {String} editorId The name used when caching the view.  Subsequent calls to this method with the same editorId will use the cached version.
 *  @param {String} editorStyle The name of the style to use when fetching the BlockContainer.
 *  @param {String} beanPath The path of the bean to include in the request.
 *  @param {Object} modelProps Optional object containing properties to be set on the default model.
 *  @param {Object} viewProps Optional object containing properties to be set on the default view.
 *  @param {Object} boneCaller The object that is requesting the BlockContainer (used for setting the opener property).
 *  @param {Object} callbackInfo An object consisting of a method property (the actual function instance to call) and an optional scope property (the object to call the method on using apply).
 *  @param {Object} parentNode The parentNode to which the Block editor should be append
*/
microstrategy.openDataBasedBlockEditor = function(editorId, editorStyle, beanPath, modelProps, viewProps, boneCaller, callbackInfo, parentNode) {
    //@class=microstrategy;@method=openDataBasedBlockEditor;
    try {
        var e = this.getBlockEditorFromCache(editorId, modelProps, viewProps, boneCaller, parentNode);
        if (e) return;
        
        var beanPathTokens = beanPath.split('.');
        var req; 
             
        if (microstrategy.EXECUTION_SCOPE == microstrategy.RWD_EXECUTION) {
            req = new mstr.http.RwBlockLoaderInput(editorStyle, beanPathTokens[beanPathTokens.length-1]);
        } else {
            // For Reports we need the Report Bean, but the beanPath is always the vb
            req = new mstr.http.ReportBlockLoaderInput(editorStyle, beanPathTokens[beanPathTokens.length-2]);
        }
        microstrategy.overwriteRequestParameters(req, modelProps, viewProps);
            
        this.openBlockEditor(editorId, req, boneCaller, callbackInfo, parentNode);
        
    } catch(err) {
        microstrategy.errors.log(err);
    }
};

/**
 *  This method uses the task infrastructure to request a FolderBean based BlockContainer from the server.
 *  @memberOf microstrategy
 *  @param {String} editorId The name used when caching the view.  Subsequent calls to this method with the same editorId will use the cached version.
 *  @param {String} editorStyle The name of the style to use when fetching the BlockContainer.
 *  @param {Object} modelProps Optional object containing properties to be set on the default model.
 *  @param {Object} viewProps Optional object containing properties to be set on the default view.
 *  @param {Object} boneCaller The object that is requesting the BlockContainer (used for setting the opener property).
 *  @param {Object} callbackInfo An object consisting of a method property (the actual function instance to call) and an optional scope property (the object to call the method on using apply).
 *  @param {Object} parentNode The parentNode to which the Block editor should be appended
*/
microstrategy.openFolderBasedBlockEditor = function(editorId, editorStyle, folderProps, modelProps, viewProps, boneCaller, callbackInfo, parentNode) {
    //@class=microstrategy;@method=openFolderBasedBlockEditor;
    try {
        var e = this.getBlockEditorFromCache(editorId, modelProps, viewProps, boneCaller, parentNode);
        if (e) return;
        
        var req = new mstr.http.FolderBlockLoaderInput(editorStyle, folderProps);
        microstrategy.overwriteRequestParameters(req, modelProps, viewProps);
            
        this.openBlockEditor(editorId, req, boneCaller, callbackInfo, parentNode);
    } catch(err) {
        microstrategy.errors.log(err);
    }
};

/**
 *  This method uses the task infrastructure to request a non Bean based BlockContainer from the server.
 *  @memberOf microstrategy
 *  @param {String} editorId The name used when caching the view.  Subsequent calls to this method with the same editorId will use the cached version.
 *  @param {String} editorStyle The name of the style to use when fetching the BlockContainer.
 *  @param {Object} modelProps Optional object containing properties to be set on the default model.
 *  @param {Object} viewProps Optional object containing properties to be set on the default view.
 *  @param {Object} boneCaller The object that is requesting the BlockContainer (used for setting the opener property).
 *  @param {Object} callbackInfo An object consisting of a method property (the actual function instance to call) and an optional scope property (the object to call the method on using apply).
 *  @param {Object} parentNode The parentNode to which the Block editor should be appended
*/
microstrategy.openBlockLoaderEditor = function(editorId, editorStyle, modelProps, viewProps, boneCaller, callbackInfo, parentNode) {
    //@class=microstrategy;@method=openBlockLoaderEditor;
    try {
        var e = this.getBlockEditorFromCache(editorId, modelProps, viewProps, boneCaller, parentNode);
        if (e) return;
        
        var req = new mstr.http.BlockLoaderInput(editorStyle);
        microstrategy.overwriteRequestParameters(req, modelProps, viewProps);
            
        this.openBlockEditor(editorId, req, boneCaller, callbackInfo, parentNode);
    } catch(err) {
        microstrategy.errors.log(err);
    }
};


/**
 *  This method gets the editor object from cache and updates the properties with the given parameters.
 *  @memberOf microstrategy
 *  @param {String} editorId The name used when caching the view.  Subsequent calls to this method with the same editorId will use the cached version.
 *  @param {Object} modelProps Optional object containing properties to be set on the default model.
 *  @param {Object} viewProps Optional object containing properties to be set on the default view.
 *  @param {Object} boneCaller The object that is requesting the BlockContainer (used for setting the opener property).
 *  @param {Object} parentNode The parentNode to which the Block editor should be appended.
 *  @returns {Object} The editor object.
*/
microstrategy.getBlockEditorFromCache = function(editorId, modelProps, viewProps, boneCaller, parentNode) {
    //@class=microstrategy;@method=getBlockEditorFromCache;
    try {
        var editor = mstr.bones.editors.Map[this.id] && mstr.bones.editors.Map[this.id][editorId];
        if (editor && !editor.get('avoidCache')) {
            var p;
            var m = editor.getModel();
            for (p in modelProps) {
                m.setPropertyByPath(p, modelProps[p]);
            }
            if (m && boneCaller) m.set('opener', boneCaller);

            for (p in viewProps) {
                editor.setPropertyByPath(p, viewProps[p]);
            }
            if (boneCaller) editor.set('opener', boneCaller);
            
            // TQMS #339619: If the parent node is supplied then reset the parentNode of the editors element.  This is needed
            // because the doc viewer gets replaced and the cached editor stays in the replaced element.
            var el = editor.get('element');
            if (parentNode && !mstr.utils.Dom.containsElement(parentNode, el, false)) {
                parentNode.appendChild(el);
            }
            
            editor.set("visible", true);
            
            return editor;
        }
    } catch(err) {
        microstrategy.errors.log(err);
    }
    return null;
};

/**
 *  This method uses the task infrastructure to request a BlockContainer from the server.
 *  @memberOf microstrategy
 *  @param {String} editorId The name used when caching the view.  Subsequent calls to this method with the same editorId will use the cached version.
 *  @param {Object} req The task request.
 *  @param {Object} boneCaller The object that is requesting the BlockContainer (used for setting the opener property).
 *  @param {Object} callbackInfo An object consisting of a method property (the actual function instance to call) and an optional scope property (the object to call the method on using apply).
 *  @param {Object} parentNode The parentNode to which the Block editor should be appended
*/
microstrategy.openBlockEditor = function(editorId, req, boneCaller, callbackInfo, parentNode) {
    //@class=microstrategy;@method=openBlockEditor;
    try {
        // Disable the wait dialog in IE
        if (mstr.utils.ISIE4) self.supressWaitPage = true;
    
            var ta = document.createElement("textarea");
            ta.setAttribute("id", editorId + "_ta");
            ta.className = "mstrJSON";
            if (parentNode) {
            	parentNode.appendChild(ta);
            } else {
	            document.body.appendChild(ta);
	        }
            
            if (!this.taskModel) {
                this.taskModel = new mstr.models.TaskModel({ parent: this });
                        
                mstr.controllers.Factory.add(this.taskModel);
                var zz = this.taskModel && this.taskModel.init && this.taskModel.init();
                
                if (!('id' in this)) {
                    mstr.controllers.Factory.add(this);
                }
                
                this.taskModel.attachEventListener(this, "set_readyState", "handleTaskModelReadyStateChange");
            }

            this.taskModel.execFetchBlock(req, ta, { 
                'editorId': editorId, 
                opener: boneCaller, 
                callback: callbackInfo 
            }); 
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
} 

/**
 * The method handles the error when the task model call fails. It either creates an action to 
 * refresh the page or just only logs the error.
 * @memberOf microstrategy
 * @param {Event} evt The mstr event object {@link mstr.lang.Event}.
 * @refactoring Used once in models.js, but that code needs to be refactored.
 */
microstrategy.handleTaskModelError = function(evt) {
    if (mstr.utils.ISIE4) self.supressWaitPage = false;
    rc = evt.src.get('requestContext');
    var err = microstrategy.descriptors.getDescriptor(7484);//'Task call failed; this could be due to a disconnection with the web server.';
    if (rc && rc.response) {
        if (rc.response.taskErrorCode) {
	        switch (rc.response.taskErrorCode){
	            case microstrategy.WEB_API_ERROR_CODES.MSI_SERVER_NAME_NOT_INITIALIZED:
	            case microstrategy.WEB_API_ERROR_CODES.MSI_INVALID_SESSION_ID:
	            case microstrategy.WEB_API_ERROR_CODES.E_MSI_USERMGR_USER_NOTFOUND:
	            case microstrategy.WEB_API_ERROR_CODES.E_MSI_CONNECT_FAILED:
	                this.updateManager.refreshPage();
	                return ;
	            default:
	                err = err + microstrategy.descriptors.getDescriptor(7485) + rc.response.taskErrorCode;
	                //Report error using error.log
	                break;
	        }
        }

        if (rc.response.data) {
            err = err + '\n' + rc.response.data ;
        } else if (rc.response.status && rc.response.statusText) {
            err = err + '\n' + rc.response.status + ': ' + rc.response.statusText;
        }
    }
    showMessage({contents:err, elements:microstrategy.OK_BUTTON, type:mstrMsgBoxImpl.MSG_WARNING});
}

/**
 * The method handles the conditions when the ready state of the task model is changed. If the current ready state is error,
 * it forwards the event to the error handling function. If the ready state is idle, it renders the default view. If the 
 * ready state is canceled, it does nothing. The callback function defined in the memo object in event is called at the 
 * end of each condition. 
 * @memberOf microstrategy
 * @param {Event} The mstr event object {@link mstr.lang.Event}.
 */
microstrategy.handleTaskModelReadyStateChange = function(evt) {
    //@class=microstrategy;@method=handleTaskModelReadyStateChange;
    try {
        // Get the request context.
        var rc = evt.src.get('requestContext');
        
        // Create the callback handler.
        var callbackFn = function () {
            // Enable the wait dialog in IE
            if (mstr.utils.ISIE4) self.supressWaitPage = false;

            var cb = rc && rc.memo && rc.memo.callback;
            // Check for a callback info object.
            if (cb) {
                // If there is both a scope and method then apply the method with the supplied scope...
                if (cb.scope) {
                    cb.method.apply(cb.scope, [evt]);
                
                // otherwise, just call the method.
                } else if (cb.method) {
                    cb.method(evt);
                }
            }
        };
        
        switch (evt.memo.value) {
        case mstr.Enum.Widget.READYSTATE.ERROR:
            // Handle the error.
            microstrategy.handleTaskModelError(evt);
            
            // Notify the callback that the request is complete.
            callbackFn();            
            return;
            
        case mstr.Enum.Widget.READYSTATE.IDLE:
            var map = mstr.bones.editors.Map[this.id] || {};
            
            var v = evt.src.get("views");
            
            // Step through models and view and set the opener (if present)
            var o = rc && rc.memo && rc.memo.opener;
            if (o) {
                var i;
                for (i = 0; v && i < v.length; i++) {
                    v[i].set('opener', o);
                }

                var m = evt.src.get("models");
                for (i = 0; m && i < m.length; i++) {
                    m[i].set('opener', o);
                }
            }
            
            // Render the default view.
            var editor = map[rc.memo.editorId] = v[0];
            editor.render();

            // Notify the callback that the request is complete. 
            callbackFn();            
            
            mstr.bones.editors.Map[this.id] = map;
            break;
            
        case mstr.Enum.Widget.READYSTATE.CANCELLED:
            // Notify the callback that the request is complete. 
            callbackFn();            
            break;
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
}

// ********************** DND HELPER OBJECT ***************************************
//<script>
//properties
mstrDNDHelperImpl.prototype = {};
mstrDNDHelperImpl.prototype.helperImg = null;
mstrDNDHelperImpl.prototype.parentBone = null;

/**
 * The event handler of mouse up event when the user releases the mouse button during drag and drop.
 * @memberOf mstrDNDHelperImpl
 * @param {String} path The path string used to retrieve the bone to detach the even from its listener. 
 */
mstrDNDHelperImpl.prototype.onmouseup = function(path) {
    //@class=mstrDNDHelperImpl;@method=onmouseup;
    try {
        if (typeof(mstr)!='undefined') {
           this.parentBone.detachWinListener(path,'mousemove');
           this.parentBone.detachWinListener(path,'mouseup');
        } else {
            document.onmousemove = null;
            document.onmouseup = null;
        }
        this.parkHelperImage();
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
}

/**
 * Hides the object by moving its position to the far left corner outside of the window.
 * @memberOf mstrDNDHelperImpl
 * @param {HTMLElememnt} obj The HTMLElement to be hided.
 */
mstrDNDHelperImpl.prototype.parkObject = function(obj) {
    //@class=mstrDNDHelperImpl;@method=parkObject;
    try {
        obj.style.top = "-10000px";
        obj.style.left = "-10000px";
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
}

/**
 * Hides the helper image.
 * @memberOf mstrDNDHelperImpl
 */
mstrDNDHelperImpl.prototype.parkHelperImage = function() {
    //@class=mstrDNDHelperImpl;@method=parkHelperImage;
    try {
        if (this.helperImg) {
            this.parkObject(this.helperImg);
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
}

/**
 * Moves the helper image close to the position where the current mouse is located.
 * @memberOf mstrDNDHelperImpl
 * @param {HTMLEvent} e The event object (W3C complaint browsers only).
 */
mstrDNDHelperImpl.prototype.moveHelperImage = function(e) {
    //@class=mstrDNDHelperImpl;@method=moveHelperImage;
    try {
        if (!this.helperImg) this.initElement();
    
        getMouse(e);
        this.helperImg.style.left = (lMouseX + 10) + "px";
        this.helperImg.style.top = (lMouseY - 20) + "px";
        var mask = microstrategy.findAncestor(getEventTarget(e));
        if (mask != null) {
            var bone = this.getMaskedBone(mask);
            if (bone != null && bone.getDNDHelperImage) {
                var imageSrc = bone.getDNDHelperImage(this.parentBone, mask.getAttribute(microstrategy.HTMLATTR_POINTS_TO));
                if (imageSrc != null && this.helperImg.src.search(new RegExp(imageSrc)) == -1) {
                    this.helperImg.src = imageSrc;
                }
                return;
            }
        }
        this.parkHelperImage();
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
}

/**
 * Gets the bone object associated to the drag-and-drop mask.
 * @memberOf mstrDNDHelperImpl
 * @param {HTMLElement} mark The HTMLElement object that represents the mask object. 
 * @returns {mstrBoneImpl} The found bone object or null.
 */
mstrDNDHelperImpl.prototype.getMaskedBone = function(mask) {
    //@class=mstrDNDHelperImpl;@method=getMaskedBone;
    try {
        var bone = microstrategy.boneForMask(mask);
        return (bone != null && bone.ondrop) ? bone : null;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return null;
    }
}

/**
 * Creates an image object and then makes it invisible by placing it out side the window.
 * @memberOf mstrDNDHelperImpl 
 */
mstrDNDHelperImpl.prototype.initElement = function() {
    //@class=mstrDNDHelperImpl;@method=initElement;
    try {
	    var img = document.createElement("img");
	    img.src = microstrategy.FOLDER_IMAGES + "1ptrans.gif";
	    img.style.position = "absolute";
	    img.style.top = img.style.left = "-10000px";
	    img.style.zIndex = 1000;
	    
	    //TQMS#352994- explicitly set image style width/height to 'auto' for IE; 
	    //Otherwise, IE will stick to the image size at 1x1 when we update image SRC to a larger image later.
	    if (bIsIE6) {
			img.style.height = 'auto';
			img.style.width = 'auto';
		 }
	    this.helperImg = document.body.appendChild(img);
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
}

/**
 * @class A helper object that bones use for accomplishing drag and drop operations.
 * @memberOf mstrDNDHelperImpl
 * @param {mstrBoneImpl} obj The bone that is requesting help for dnd.
 */
function mstrDNDHelperImpl(obj) {
    //@class=mstrDNDHelperImpl;@method=constructor;
    this.parentBone = obj;
    return this;
}

/**
 * Registers the candidate bones from microstrategy.bonesToRegister list. After the registration, clears the list. 
 * @memberOf microstrategy
 */
microstrategy.registerNewBones = function () {
    for (var i=0,len = microstrategy.bonesToRegister.length; i < len; i++){
        var boneProp = microstrategy.bonesToRegister[i];
        microstrategy.registerBone(boneProp.id, boneProp.loadCondition, boneProp.properties);
    }
    microstrategy.bonesToRegister.length = 0;
}

/**
 * Creates an attribute string for an XML element.
 * @memberOf microstrategy
 * @param {String} name The name of the attribute.
 * @param {String} value The value of the attribute.
 * @returns {String} The name-value pair for the XML element attribute. 
 */
microstrategy.addXmlAttr = function(name, value) {
    //@class=microstrategy;@method=addXmlAttr;
    try {
        // TODO: Add encodding
        return " " + name + '="' + value + '"';
    }
    catch(err) {
        microstrategy.errors.log(err);
        return 0;
    }
}

/**
 * Creates an attribute string for an XML element. The value string of the attribute is encoded.
 * @memberOf microstrategy
 * @param {String} name The name of the attribute.
 * @param {String} value The value of the attribute.
 * @returns {String} The name-value pair of the XML attribute.
 */
microstrategy.addXmlAttrEncoded = function(name, value) {
	if (! value) {
		return "";
	}
	var buf = [];
	var len = value.length;
	var ch;
	for (var i = 0; i < len; i++) {
		ch = value.charAt(i);
		switch (ch) {
		case '>':
			buf.push("&gt;");
			break;
		case '<':
			buf.push("&lt;");
			break;
		case '&':
			buf.push("&amp;");
			break;
		case '\u0009':
			buf.push("&#x09;"); // tab
			break;
		case '\n':
			buf.push("&#x0A;"); // line feed
			break;
		case '\r':
			buf.push("&#x0D;"); // carriage return
			break;
		case '"':
			buf.push("&quot;"); // 
			break;
		default:
			buf.push(ch);
		break;
		}
	}
	return ' ' + name + '="' + buf.join("") + '"';
}

/**
 * Gets the popup mask object and set the visibility of the object to be true.
 * @memberOf microstrategy
 * @param {Object} elem The element that contains the popupMask object.
 * @returns {HTMLElement} The popup mask object.
 */
microstrategy.getPopupMask = function(elem) {
    // refactored from dhtml.js
    var __result = elem && elem.popupMask;    
    
    if(!__result) {
    
        // Gets the popupMask objects and puts them into the JavaScript document object.
    	if (!document["popupMasks"]) {
    		document["popupMasks"] = [];

    		var popupMasks = document.getElementsByName("popupMask");
    		if (popupMasks) {
    			for (var i = 0, len =  popupMasks.length; i < len; i++) {
    				popupMasks[i].setAttribute("free", true);
    				document["popupMasks"].push(popupMasks[i]);
    			}
    		}
    	}
        
        var availableMasks = document["popupMasks"];
        for (var i = 0; i < availableMasks.length; i++) {
            if (availableMasks[i].getAttribute("free") == true) {
                __result = availableMasks[i];
                break;
            }
        }
    
        if(!__result) {
            var popupMask = document.getElementById('popupMask1');
            var newBackground;
        
            if (popupMask) {
                newBackground = popupMask.cloneNode(false);
            } else {
                newBackground = document.createElement("iframe");
            }
            document.body.appendChild(newBackground);
            newBackground.style.position = "absolute";
            newBackground.style.visibility = "hidden";
            newBackground.style.display = "none";
            newBackground.setAttribute("border", "0");
            newBackground.id = "popupMask" + availableMasks.length;
        
            availableMasks.push(newBackground);
            
            __result = newBackground;
        }
    }
    
    if(__result) {
        __result.setAttribute("free", false);
        __result.style.display = "block";
        
        if(elem) {
            elem.popupMask =  __result;
            __result.elem = elem;
            elem.insertAdjacentElement("beforeBegin", __result);
            __result.style.visibility = "visible";
            __result.className = "popupmask";
        }
    }

    return __result;
}

/**
 * Releases the popup mask object. Sets the mask to be invisible and clears its element.
 * If the popup mask object is not provided, it will get the mask objects from the JavaScript document object. 
 * @memberOf microstrategy
 * @param {Object} [elem] The popup mask object.
 */
microstrategy.releasePopupMask = function(elem) {
         if (elem) {
             var popupMask = elem.popupMask;

             if (popupMask) {
                 popupMask.style.display = "none";
                 popupMask.style.visibility = "hidden";
                 popupMask.style.zIndex = 0;

                 popupMask.setAttribute("free", true);

                 popupMask.elem = null;
             }

             elem.popupMask = null;
         } else {
            var availableBackgrounds = document["popupMasks"];

            if (availableBackgrounds) {
                for (var i = 0; i < availableBackgrounds.length; i++) {
                    availableBackgrounds[i].style.display = "none";
                    availableBackgrounds[i].style.visibility = "hidden";
                    availableBackgrounds[i].style.zIndex = 0;

                    availableBackgrounds[i].setAttribute("free", true);

                    var associatedElem = availableBackgrounds[i].elem;
                    if (associatedElem) {
                        associatedElem.popupMask = null;
                    }

                    availableBackgrounds[i].elem = null;
                }
            }
         }
}

/**
 * The method creates a report/document execution action based on the information from a link object, and then it invokes 
 * the update manager to flush and submit the changes.
 * @memberOf microstrategy 
 * @param {Object} linkInfo An object that contains the information of the link.
 * @param {String} linkInfo.tstp The sub type string.
 * @param {String} linkInfo.tty The DSS type of the object, can be either report (value 3) or document (value 55).
 * @param {String} linkInfo.tid The report of document id.
 * @param {String} xml The xml data passed into the report/document execution action.
 * @param {Boolean} onw The new window flag passing to the update manager. 
 */
microstrategy.execDynamiclLink = function(linkInfo, xml,onw) {
//@class=mstrGridReport; @method=execDynamicLink;
    try {
        var argNames = null;
        var argValues = [linkInfo.tid];
        
        // Argument IDs will change, with new event definition
        var event = null;
        var tvm = null;
        if (linkInfo.tty == microstrategy.DSSTYPE_RPT_DEFINITION) {
            event = mstrUpdateManager.RUN_REPORT;
            argNames = ['1001'];
     	    //TQMS 352141. We don't need to send link XML if link has no answers.
            if (xml) {
            	argNames.push('4222');
		        argValues.push(xml);
            }
            argNames.push('4115');
            argValues.push(microstrategy.getReportViewMode(linkInfo.tstp));
        } else if  (linkInfo.tty == microstrategy.DSSTYPE_DOC_DEFINITION) {
            if (linkInfo.tstp == microstrategy.DSSSUB_TYPE_RW) {
                event = mstrUpdateManager.RUN_RW_DOCUMENT;
                argNames = ['2048001'];
	            if (xml) {
	            	argNames.push('2048140');
			        argValues.push(xml);
	            }
            } else {
                event = mstrUpdateManager.RUN_DOCUMENT;
                argNames = ['1001'];
	            if (xml) {
	            	argNames.push('32351');
			        argValues.push(xml);
	            }
            }
        }
    
	    var um = microstrategy.updateManager;
        var oldUseIframeSetting = um.useIframe;
        var oldNWSetting = um.newWindow;
    
        um.useIframe = false;
        um.newWindow = onw;
        if(um.hasChangesToSubmit()){
        	um.add([um.createActionObject(null, mstrUpdateManager.APPLY_CHANGES, mstrUpdateManager.applyChangesBeanPath, [], [], [])]);
        }
                    
        um.add([um.createActionObject(this.elem, event, "", argNames, argValues, [])]);
        um.flushAndSubmitChanges();
        um.acknowledgeRequest();
        um.newWindow = oldNWSetting;
        um.useIframe = oldUseIframeSetting;
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
}

/**
 * Gets the report view mode based on provided the sub type from the link.
 * @memberOf microstrategy
 * @param {String} subType The sub type string.
 * @returns {Integer} The report view mode. 
 * @refactoring Remove the break statement after each return statement. Only used locally in execDynamiclLink().
 * Refactor to an inline method.
 */
microstrategy.getReportViewMode = function (subType){
	            switch(subType.toString()){
				case microstrategy.DSSTYPE_GRAPH:
					return microstrategy.DISPLAY_MODE_GRAPH;
					break;
				case microstrategy.DSSTYPE_GRID_AND_GRAPH:
					return microstrategy.DISPLAY_MODE_GRID_AND_GRAPH;
					break;
                case microstrategy.DSSTYPE_GRID:
               	default:
					return microstrategy.DISPLAY_MODE_GRID;
                	break;
            }
}


/**
 * Checks if locale is double type language like Chinese, Korean or Japenese.
 * @memberOf microstrategy
 * @returns {Boolean} true if the locale is a double byte language like Chinese, Korean or Japenese.
 * @refactoring. Used only once in behavior.js. Refactor to an inline method.
 */
microstrategy.isDoubleByte = function () {
	var localeID = microstrategy.displayLocaleID; 
    
	if (localeID != null && (localeID == 1041 || localeID == 1042 || localeID == 2052 || localeID ==1028)) {
    	return true;
    }
    return false;
}

/** 
 * Load the javascript files from the array - microstrategy.mstrScriptFiles. These javascript files are supposed to be loaded in parallel.
 * used for Parallel JS.
 */
microstrategy.loadAdditionalFiles = function(s){
	microstrategy.delayOnload();
	for(var i=0, l=s.length; i<l; ++i) {            
		var sc = "script", tp = "text/javascript";            
		if (bIsFirefox){
			var t = document.createElement(sc), 
			sa = "setAttribute";                
			t[sa]("src", s[i]);                
			t[sa]("type", tp);                
			document.getElementsByTagName("head")[0].appendChild(t);
		} else	{ 
			document.writeln("<" + sc + " type=\"" + tp + "\" src=\"" + s[i] + "\" defer></" + sc + ">");
		}        
	}
}

/**
 * Point to the window.onload function and will be called until all of the inline scripts inside the wrapper function - 
 * microstrategy.mstrInlineScripts get executed. 
 * used for Parallel JS.
 */
microstrategy.mstrOnLoadFn = null;

/** 
 * Delay calling window.onload until all of the inline scripts inside the wrapper function - microstrategy.mstrInlineScripts get executed.
 * used for Parallel JS.
 */
microstrategy.delayOnload = function(){
	if (typeof (window.onload) == 'function') {
		microstrategy.mstrOnLoadFn = window.onload;
		window.onload = null;
		//In FF 3.0.14, we observed that the onload function in the <body> is still be called even we set it to be null here.
		//That will cause the onload() called twice (once in the post load js, and another one right after that). So for FF3.0
		//we will remove the onload function here to avoid the onload being called twice.
		if(mstr.utils.ISFF3_0) document.body.removeAttribute("onload");
	} 
}

/**
 * Get zoom factor, used for widgets to read.
 */
microstrategy.getZoomFactor = function(){
    return microstrategy.ZOOM_FACTOR;
}

/**
 * Get persist parameters, used by flash.
 */
microstrategy.getPersistParams = function(){
    return microstrategy.persistParams;
}

//array of dynamic JS files requested by iframe/xhr.
//array will be populated by insertDynamicScript( ).
microstrategy.dynamicJS = [];

/**
 * dynamically insert <script> tag into <header> section
 * When current <script> is ready (js code loaded/parsed), start processing next one.
 * This is for IE browsers only.
 */
microstrategy.insertScriptTag = function(jsfile, e, notify){
	var script = document.createElement("script");
	var sa = "setAttribute";
	script[sa]("src", jsfile);
	script[sa]("type", "text/javascript");
	script[sa]("defer", 'defer');
	document.getElementsByTagName("head")[0].appendChild(script);
	
	
	if (bIsIE4) {
		//IE: handle <script> Tag state change event:
		script.onreadystatechange = function(){
			//when IE finishes loading/parsing current <script>, continue next
			if (script.readyState == "loaded" || script.readyState == "complete"){
				script.onreadystatechange = null; //avoid handling twice
				microstrategy.loadDynamicJS(e, notify); //continue loading next
			}
		}
	} else if (mstr.utils.ISSAFARI) {
		script.onload = function(){
			script.onload = null; //avoid handling twice
			microstrategy.loadDynamicJS(e, notify); //continue loading next
		}	
	}
}

/**
 * process dynamic JS files.
 * Working together with microstrategy.insertScriptTag() to insert one <script> tag into <header> section for each dynamic JS file 
 * This is for IE browsers only.
 */
microstrategy.loadDynamicJS = function(e, notify) {
	if ((bIsIE4 || mstr.utils.ISSAFARI) && microstrategy.dynamicJS.length > 0) {
		if (!checkJSExists(microstrategy.dynamicJS[0]['key'])) { //if first file is not loaded yet
			microstrategy.insertScriptTag(microstrategy.dynamicJS[0]['file'], e, notify);
			microstrategy.dynamicJS.shift(); //pop out the first item
		}
		else { //otherwise, pop out the first item, continue to process next file
			microstrategy.dynamicJS.shift();
			microstrategy.loadDynamicJS(e, notify);
		}
	} else if (notify) {
		microstrategy.eventManager.initializeBones(e);
	}
}

/**
 * An asynchronous javascript file loader. 
 */
microstrategy.jsLoader = {
    /**
     * Status of a file whose script tag has been inserted but onload has not yet fired. 
     */
    LOADING: 1,
    /**
     * Status of a file whose script tag has fired its onload already. 
     */
    LOADED: 2,
    /** 
     * Hashtable of file names that have been requested. Key = file path+name, value = LOADING or LOADED. 
     */
    status: {},
    /**
     * <p>Checks if a given file has been requested. If not, requests it with a given callback;
     * if so, checks if load still pending; if so, overwrites the callback, otherwise calls the given
     * callback immediately.</p>
     * @param {String} file The file name (path is optional).
     * @param {Boolean} isBundle If true, indicates that the given file is just a name and should have the
     * javascript bundle path prefix added to it.
     * @param {Function} [callback] Optional function to call once the file is loaded. If null, the
     * previous callback (if any) is left intact.
     */
    get: function(file, isBundle, callback){
        // If no file is passed in, do the callback immediately and exit.
        if (!file) {
            if (callback) {
                callback();
            }
            return;
        }
        if (isBundle) {
            // TO DO: is it OK to hard-code this path for JSPs & ASPs?
            file = "../javascript/bundles/" + file;
        }
        var st = this.status,
            s = st[file];
        if (!s) {
            // file has not been requested yet; load it now
            st[file] = {state: this.LOADING, callback: callback};
            this.insertScript(file);
        } else if (s.state === this.LOADING) {
            // file load in progress; update the callback only if a new one is given
            if (callback) {
                s.callback = callback;
            }
        } else if (s.state === this.LOADED) {
            // file load complete, do the given callback (if any) immediately
            if (callback) {
                callback();
            }
        }
    },
    /**
     * <p>Inserts a &lt;script&gt; tag for a given file into the document header .</p>
     * <p>The script tag's onload is set to callback this object's onFileLoad method, which manages
     * the firing of the latest callback specified for this file.</p>
     * @param {String} file The file name (without a path).
     */
    insertScript: function(file){
        var el = document.createElement('script'),
            sa = "setAttribute",
            that = this;
        el[sa]("src", file);
        el[sa]("type", "text/javascript");
        el[sa]("defer", 'defer');
        el.onload = function () {
            el.onload = null; //avoid handling twice
            that.onFileLoad(file);
            that = null;
        }; 
        el.onreadystatechange = function(){
            var rs = el.readyState;
            if (rs === "loaded" || rs === "complete"){
                el.onreadystatechange = null; //avoid handling twice
                that.onFileLoad(file);
                that = null;
            }
        };        
        document.getElementsByTagName("head")[0].appendChild(el);
    },
    /**
     * The callback for script files dynamically inserted by this object.  Manages the firing of
     * the latest callback (if any) specified for this file.</p>
     * @param {String} file The file path+name (typically a relative URL).
     */
    onFileLoad: function(file){
        var st = this.status[file] || {},
            f = st.callback;
        st.state = this.LOADED;
        if (f) {
            f();
        }
    }
};

/**
 * A loader for Mojo javascript that adds a Mojo bundle to a page without Mojo code.
 * Allows any page with "microstrategy" object to insert Mojo content.
 */
microstrategy.mojoLoader = {

    /**
     * Uses microstrategy.jsLoader to load a given Mojo bundle (if not already loaded)
     * and to trigger a callback which instantiates a given Mojo class.
     * @param {Object} config Specification for Mojo bundle and class to be loaded.
     * @param {String} config.bundle Name of Mojo javascript bundle file (without path) to be loaded (if not already).
     * @param {String} config.scriptClass Fully qualified class name of Mojo JSON to be instantiated after file load.
     * This JSON is assumed to be a definition for a Mojo class instance that can be created using "mstrmojo.insert()".
     * @param {String} config.id Id to be assigned to the Mojo class instance once it is created.
     * @param {String} [config.placeholder] Placeholder to be assigned to the Mojo class instance once it is created.
     * @param {Function} [config.callback] Optional callback to be called once class is instantiated successfully.
     */
	loadWidget : function(config) {
        var me = this;
        microstrategy.jsLoader.get(
            config.bundle,
            true,
            function(){
                me.onload(config);
                me = null;
            });
	},	
		
    /**
     * Callback from loadWidget method, fired after given bundle is ensured to be loaded.
     * @param {Object} config See loadWidget method for details.
     */
	onload: function (config) {
	    // Have we created the widget yet?
	    var w = mstrmojo.all[config.id];
	    if (!w) {
	        // Create it now.
	        // Fetch the JSON definition for it.
	        var sc = config.scriptClass,
	           json = mstrmojo[sc];
	        if (!json) {
	            mstrmojo.requiresCls("mstrmojo." + sc);
	            json = mstrmojo[sc];
	            if (!json) {
	                return;
	            }
	        }
	        // Instantiate a widget from the JSON.
	        w = mstrmojo.insert(json);
	        if (!w) {
	            return;
	        }
	        // Give a placeholder DOM node.
	        var p = config.placeholder;
	        if (p) {
    	        w.placeholder = p;
	        }
	    }		
	    if (config.callback) {
	        config.callback();
	    }	
	}
};


